Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is this a safe way to use ulid concurrently with other libraries too? #79

Closed
frederikhors opened this issue Jun 11, 2022 · 7 comments
Closed

Comments

@frederikhors
Copy link

I just asked this question on SO. I'm posting this here too both for me and for for future "researchers".

I'm trying to use for the first time the ulid package.

In their README they say:

Please note that rand.Rand from the math package is not safe for concurrent use.
Instantiate one per long living go-routine or use a sync.Pool if you want to avoid the potential contention of a locked rand.Source as its been frequently observed in the package level functions.

Can you help me understand what does this mean and how to write SAFE code for concurrent use with libraries such ent or gqlgen?

Example: I'm using the below code in my app to generate new IDs (sometimes even many of them in the same millisecond which is fine for 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()
}

Is this a safe way to use the package?

Can you help me better understand?

@tsenart
Copy link
Contributor

tsenart commented Jun 11, 2022

Can you help me understand what does this mean and how to write SAFE code for concurrent use with libraries such ent or gqlgen?

Here are a few links relevant to the topic of thread safe random number generation in Go:

If you don't care that there is contention on a locked random number generator across go-routines, use this: https://pkg.go.dev/golang.org/x/exp/rand#example-LockedSource. I will update the README with this recommendation, since it seems most users of ulid don't want to define their own thread safe entropy source, nor manage a sync.Pool.

If you find there's too much contention in your program in production (via profiling with pprof), you can implement the sync.Pool solution.

@tsenart
Copy link
Contributor

tsenart commented Jun 11, 2022

I opened #80 to improve the README.

@tsenart
Copy link
Contributor

tsenart commented Jun 11, 2022

As a follow up, here's a proposal for a ulid.Make() function that has sane defaults and is safe for concurrent use: #81

@frederikhors
Copy link
Author

The method described here is really fast! Can we use it with ulid?

@peterbourgon
Copy link
Member

The method described here is really fast! Can we use it with ulid?

Of course. Just create an io.Reader that uses this as a source of entropy.

@frederikhors
Copy link
Author

The method described here is really fast! Can we use it with ulid?

Of course. Just create an io.Reader that uses this as a source of entropy.

Can you show me an example please?

@tsenart tsenart closed this as completed Jun 22, 2022
@tsenart
Copy link
Contributor

tsenart commented Jun 22, 2022

Merged #81

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants