Является ли это безопасным способом одновременного использования ulid с другими библиотеками?
Я пытаюсь использовать в первый раз пакет ulid .
В своем README они говорят:
Обратите внимание, что
rand.Rand
изmath
package небезопасен для одновременного использования. Создайте один экземпляр для каждой долгоживущей процедуры или используйтеsync.Pool
если вы хотите избежать потенциальной конкуренции заблокированногоrand.Source
как это часто наблюдается в функциях уровня пакета.
Можете ли вы помочь мне понять, что это значит и как написать БЕЗОПАСНЫЙ код для одновременного использования с такими библиотеками, как ent или gqlgen?
Пример: я использую приведенный ниже код в своем приложении для создания новых идентификаторов (иногда даже многих из них за одну миллисекунду, что подходит дляulid
).
import (
"math/rand"
"time"
"github.com/oklog/ulid/v2"
)
var defaultEntropySource *ulid.MonotonicEntropy
func init() {
defaultEntropySource = ulid.Monotonic(rand.New(rand.NewSource(time.Now().UnixNano())), 0)
}
func NewID() string {
return ulid.MustNew(ulid.Timestamp(time.Now()), defaultEntropySource).String()
}
Это безопасный способ использования пакета?
1 ответ
Это безопасный способ использования пакета?
Нет, это предложение предполагает, что каждый rand.Source должен быть локальным для горутины, вашейdefaultEntropySource
rand.Source часть потенциально может быть разделена между несколькими горутинами.
Как описано в New function, вам нужно только убедиться, что читатель энтропии безопасен для одновременного использования, а Monotonic — нет. Вот два способа реализации предложения документации:
Создайте один rand.Source для каждого вызова NewID(), выделяет новую энтропию для каждого вызова NewID
func NewID() string {
defaultEntropySource := ulid.Monotonic(rand.New(rand.NewSource(time.Now().UnixNano())), 0)
return ulid.MustNew(ulid.Timestamp(time.Now()), defaultEntropySource).String()
}
Как и выше, но с использованием sync.Pool для возможного повторного использования ранее выделенногоrand.Source
с
var entropyPool = sync.Pool{
New: func() any {
entropy := ulid.Monotonic(rand.New(rand.NewSource(time.Now().UnixNano())), 0)
return entropy
},
}
func NewID() string {
e := entropyPool.Get().(*ulid.MonotonicEntropy)
s := ulid.MustNew(ulid.Timestamp(time.Now()), e).String()
entropyPool.Put(e)
return s
}