|
8 | 8 | import Foundation |
9 | 9 | import Hub |
10 | 10 | import Jinja |
| 11 | +import os |
11 | 12 |
|
12 | 13 | /// A type alias for chat messages, represented as key-value pairs. |
13 | 14 | public typealias Message = [String: any Sendable] |
@@ -609,11 +610,8 @@ public class PreTrainedTokenizer: @unchecked Sendable, Tokenizer { |
609 | 610 |
|
610 | 611 | private let cleanUpTokenizationSpaces: Bool |
611 | 612 |
|
612 | | - /// Cache for compiled Jinja templates keyed by their literal template string |
613 | | - private var compiledChatTemplateCache: [String: Template] = [:] |
614 | | - |
615 | | - /// Lock to protect the compiled chat template cache from concurrent access |
616 | | - private let cacheLock = NSLock() |
| 613 | + /// Thread-safe cache for compiled Jinja templates keyed by their literal template string |
| 614 | + private let templateCache = OSAllocatedUnfairLock(initialState: [String: Template]()) |
617 | 615 |
|
618 | 616 | /// Initializes a tokenizer from Hugging Face configuration files. |
619 | 617 | /// |
@@ -775,28 +773,22 @@ public class PreTrainedTokenizer: @unchecked Sendable, Tokenizer { |
775 | 773 | } |
776 | 774 |
|
777 | 775 | private func compiledTemplate(for templateString: String) throws -> Template { |
778 | | - // Fast path: check cache under lock |
779 | | - cacheLock.lock() |
780 | | - if let cached = compiledChatTemplateCache[templateString] { |
781 | | - cacheLock.unlock() |
| 776 | + // Fast path: check cache |
| 777 | + if let cached = templateCache.withLock({ $0[templateString] }) { |
782 | 778 | return cached |
783 | 779 | } |
784 | | - cacheLock.unlock() |
785 | 780 |
|
786 | 781 | // Compile template outside of lock to avoid holding lock during expensive operation |
787 | 782 | let compiled = try Template(templateString) |
788 | 783 |
|
789 | | - // Insert into cache under lock (using double-checked locking pattern) |
790 | | - cacheLock.lock() |
791 | | - defer { cacheLock.unlock() } |
792 | | - |
793 | | - // Check again in case another thread compiled the same template |
794 | | - if let cached = compiledChatTemplateCache[templateString] { |
795 | | - return cached |
| 784 | + // Insert into cache (double-checked in case another thread compiled the same template) |
| 785 | + return templateCache.withLock { cache in |
| 786 | + if let cached = cache[templateString] { |
| 787 | + return cached |
| 788 | + } |
| 789 | + cache[templateString] = compiled |
| 790 | + return compiled |
796 | 791 | } |
797 | | - |
798 | | - compiledChatTemplateCache[templateString] = compiled |
799 | | - return compiled |
800 | 792 | } |
801 | 793 |
|
802 | 794 | func preTokenize(_ text: String, options: PreTokenizerOptions) -> [String] { |
|
0 commit comments