🔧 fix(token_counter): enhance token encoder caching and concurrency handling
This commit is contained in:
@@ -14,12 +14,19 @@ import (
|
|||||||
"one-api/dto"
|
"one-api/dto"
|
||||||
relaycommon "one-api/relay/common"
|
relaycommon "one-api/relay/common"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
)
|
)
|
||||||
|
|
||||||
// tokenEncoderMap won't grow after initialization
|
// tokenEncoderMap won't grow after initialization
|
||||||
var defaultTokenEncoder tokenizer.Codec
|
var defaultTokenEncoder tokenizer.Codec
|
||||||
|
|
||||||
|
// tokenEncoderMap is used to store token encoders for different models
|
||||||
|
var tokenEncoderMap = make(map[string]tokenizer.Codec)
|
||||||
|
|
||||||
|
// tokenEncoderMutex protects tokenEncoderMap for concurrent access
|
||||||
|
var tokenEncoderMutex sync.RWMutex
|
||||||
|
|
||||||
func InitTokenEncoders() {
|
func InitTokenEncoders() {
|
||||||
common.SysLog("initializing token encoders")
|
common.SysLog("initializing token encoders")
|
||||||
defaultTokenEncoder = codec.NewCl100kBase()
|
defaultTokenEncoder = codec.NewCl100kBase()
|
||||||
@@ -27,10 +34,33 @@ func InitTokenEncoders() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getTokenEncoder(model string) tokenizer.Codec {
|
func getTokenEncoder(model string) tokenizer.Codec {
|
||||||
|
// First, try to get the encoder from cache with read lock
|
||||||
|
tokenEncoderMutex.RLock()
|
||||||
|
if encoder, exists := tokenEncoderMap[model]; exists {
|
||||||
|
tokenEncoderMutex.RUnlock()
|
||||||
|
return encoder
|
||||||
|
}
|
||||||
|
tokenEncoderMutex.RUnlock()
|
||||||
|
|
||||||
|
// If not in cache, create new encoder with write lock
|
||||||
|
tokenEncoderMutex.Lock()
|
||||||
|
defer tokenEncoderMutex.Unlock()
|
||||||
|
|
||||||
|
// Double-check if another goroutine already created the encoder
|
||||||
|
if encoder, exists := tokenEncoderMap[model]; exists {
|
||||||
|
return encoder
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new encoder
|
||||||
modelCodec, err := tokenizer.ForModel(tokenizer.Model(model))
|
modelCodec, err := tokenizer.ForModel(tokenizer.Model(model))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// Cache the default encoder for this model to avoid repeated failures
|
||||||
|
tokenEncoderMap[model] = defaultTokenEncoder
|
||||||
return defaultTokenEncoder
|
return defaultTokenEncoder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cache the new encoder
|
||||||
|
tokenEncoderMap[model] = modelCodec
|
||||||
return modelCodec
|
return modelCodec
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user