Search code examples
multithreadinggogoroutinethread-local-storagemdc

Global Thread-local Storage feasibility and best Practices in Go


I am a beginner in Golang, and I would like to implement something similar to the Mapped Diagnostic Context (MDC) in Java, which is achieved through thread-local storage, in Go. However, I find it hard to find information about global thread-local storage in Go online.

I have several questions:

  • Is it possible to create a kind of global thread-local storage for each goroutine in Go to store data and context?

  • Is attempting to implement global thread-local storage considered an anti-pattern in Go?

  • Is it recommended to replace the way of passing context by implementing global thread-local storage in Go?

  • Assuming in your choice, would you prefer to use the method of passing context or would you attempt to implement a thread-local storage to save and manage context?

I've found some references to this, but I can't come to a conclusion to decide whether to implement it or not.


Solution

  • There are several issues here, which usually happen when you try to emulate features of other languages in Go.

    • Goroutines are not threads. Goroutines do not have identities like threads do.
    • Context is to store request-scope state and data. It is not a replacement for thread-local storage.
    • If you think you need thread-local storage, then you might be misusing goroutines. Thread-local storage and thread pools are usually used when thread creation is costly, so you create them once and reuse them. Do not do that in Go unless goroutine initialization is costly. For most cases, just create a new goroutine and let it run to completion.
    • If you still think you need thread local storage, consider closures:
    func f() {
       var i int
       go func() {
          // Here, use i as thread-local storage
       }()
    }
    
    • If closures do not work, pass a struct around for thread-local storage
    func f() {
      go func() {
         var t threadLocalData
         ...
         g(t)
         ...
      }{}
    }