Re: [go-nuts] How to get current goroutine id?

16,475 views
Skip to first unread message

Jesse McNelis

unread,
Oct 12, 2012, 1:23:34 AM10/12/12
to aqiansunboy, golan...@googlegroups.com
On Fri, Oct 12, 2012 at 1:55 PM, aqiansunboy <sunboy...@gmail.com> wrote:
> Hello ervery one,I want to know current goroutine id,How can I get it?

You really don't. Search the mailing list for previous threads on why.



--
=====================
http://jessta.id.au

Dave Cheney

unread,
Oct 12, 2012, 1:27:01 AM10/12/12
to Jesse McNelis, aqiansunboy, golan...@googlegroups.com
No such Id exists. This, among other reasons, to prevent programmers
for simulating thread local storage using the goroutine id as a key.
> --
>
>

吴超前

unread,
Oct 12, 2012, 6:13:28 AM10/12/12
to Dave Cheney, Jesse McNelis, golan...@googlegroups.com
Thank you,But I found a solution with the help of somebody.But I don't understand How it work.

First,creat one c file in the same directory with the other go file,the content is:
  1. #include <runtime.h>
  2. void ·GetGoId(int32 ret) {
  3. ret = g->goid;
  4. USED(&ret);
  5. }
the sample use is:
  1. package main
  2. import "fmt"
  3. func GetGoId() int32
  4. func main() {
  5. fmt.Println(GetGoId())
  6. }


2012/10/12 Dave Cheney <da...@cheney.net>

Jan Mercl

unread,
Oct 12, 2012, 6:17:13 AM10/12/12
to 吴超前, Dave Cheney, Jesse McNelis, golan...@googlegroups.com
On Fri, Oct 12, 2012 at 12:13 PM, 吴超前 <sunboy...@gmail.com> wrote:
> Thank you,But I found a solution with the help of somebody.But I don't
> understand How it work.

Please explain what problem you're trying to solve instead of
struggling to use the chosen method (which is possibly wrong).

-j

bryanturley

unread,
Oct 12, 2012, 8:54:13 PM10/12/12
to golan...@googlegroups.com, Dave Cheney, Jesse McNelis
What I do when i need something like this is

type LilSrv struct {
  // bleh
  // your goroutine local stuff here nicely predefined
  // some chans to talk to it
}

func (ls *LilSrv) MLoop() {
  for {
  // bleh, stuff
  }
}

...  somewhere in your code

ls = new(LilSrv) // or similar
go ls.MLoop()  // normally i have this wrapped in something like "NewLilSrv() (ls *LilSrv)"

now that ls is your goroutine local storage without using c code or any other way to low level for normal use code.

ps: above was typed directly into this group email thing from memory and is probably slightly wrong

minux

unread,
Oct 13, 2012, 3:33:07 AM10/13/12
to bryanturley, golan...@googlegroups.com, Dave Cheney, Jesse McNelis
Please don't use goroutine local storage. It's highly discouraged. In fact, IIRC, we used to
expose Goid, but it is hidden since we don't want people to do this.

Potential problems include:
1. when goroutine goes away, its goroutine local storage won't be GCed. (you can get goid for
the current goroutine, but you can't get a list of all running goroutines)
2. what if handler spawns goroutine itself? the new goroutine suddenly loses access to your
goroutine local storage. You can guarantee that your own code won't spawn other goroutines,
but in general you can't make sure the standard library or any 3rd party code won't do that.

thread local storage is invented to help reuse bad/legacy code that assumes global state, Go
doesn't have legacy code like that, and you really should design your code so that state is passed
explicitly and not as global (e.g. resort to goroutine local storage)

bryanturley

unread,
Oct 13, 2012, 11:12:40 AM10/13/12
to golan...@googlegroups.com

On Sat, Oct 13, 2012 at 8:54 AM, bryanturley <bryan...@gmail.com> wrote:
What I do when i need something like this is

type LilSrv struct {
  // bleh
  // your goroutine local stuff here nicely predefined
  // some chans to talk to it
}

func (ls *LilSrv) MLoop() {
  for {
  // bleh, stuff
  }
}

...  somewhere in your code

ls = new(LilSrv) // or similar
go ls.MLoop()  // normally i have this wrapped in something like "NewLilSrv() (ls *LilSrv)"

now that ls is your goroutine local storage without using c code or any other way to low level for normal use code.


Are you saying the ls in my example won't get GC'ed when it isn't in use anymore?
What I exampled here is done throughout the standard library...  for instance inside http://golang.org/src/pkg/net/http/server.go?s=30567:30613#L1015
c, e := newConn()  few lines later
go c.serve() 
I think my phrasing just confused you.
The entire idea of this was to make it not a global state, just a struct that got allocated before the goroutine started that was explicit to that goroutine and others that need to talk to it.
And if a new goroutine is started in ls.MLoop it doesn't necessarily even matter if it can see that ls.

The real problem was a single global name that lived in a new spot automagically each thread, that is clearly not happening here.

Kevin Gillette

unread,
Oct 14, 2012, 8:36:25 AM10/14/12
to golan...@googlegroups.com
That should be fine, but in this case, it'd be better to refer to it as 'task specific' instead of 'goroutine local', since your struct isn't/shouldn't be designed around the assumption that it's goroutine local.

The big issue with stuff not being freed is when a map of goroutine id to data is used (if the goroutine exits without deleting its data from the map, a leak has occurred), not to mention that there are _extremely_ few, if any (I'm strongly edging towards there being none) legitimate reasons to store data based on goroutine Id -- that kind of thinking is generally a carryover for languages that are much less effective at handling concurrency.

dam...@gmail.com

unread,
Feb 24, 2016, 12:59:11 PM2/24/16
to golang-nuts
Kevin

I have in my opinion valid reason. I'm writing a web server in go. I want to have logs across all application to include requestID. The only way I can do that is to pass httpContext everywhere! Which is hilarious, and super unclean. In other languages/frameworks it is possible as you have something like HttpContext accessible globally, and yet of course you have to deal with spawning child threads with care and maybe even to pass httpContext there but it's much smaller hustle than passing httpContext in every single function I'll write in my application.

Jesper Louis Andersen

unread,
Feb 24, 2016, 2:51:52 PM2/24/16
to dam...@gmail.com, golang-nuts

On Wed, Feb 24, 2016 at 4:39 PM, <dam...@gmail.com> wrote:
I have in my opinion valid reason. I'm writing a web server in go. I want to have logs across all application to include requestID.


Is one implementation. You should heed the advice given there though: use the 'context' package instead for these kinds of things:


Why? Because as your program grows and you start using concurrency more, you will need a way to track the context/extent of a call and clean up everything pertaining to it when you reach some kind of exit-situation. Here a simple goroutine ID won't cut it and you would need more contextual information anyway.

Another thing worth pursuing is to utilize that 'error'-return everybody likes to hate. Have your functions return errors, and log higher up the call chain. This nicely separates logging from computation. Furthermore, an error-value in the code is something the code can inspect and operate upon. A log line is more-or-less dead to the program in contrast.

This is also the approach used in many other programming languages. In my Erlang code, for instance, you often return either {ok, Value} for some succesful returned Value, or you return {error, Reason} where Reason is a term/value describing what went wrong, including structural information. The higher levels of code, which has access to the contextual information, usually have a function of the form "format_reason(Err) -> case Err of ... end." which can produce a human readable reason for logging purposes. But then again, we usually also log the error term structurally so you can use programs to inspect the logs. This usually avoids having to pass contextual data to the lower level functions, a practice which will make them less globally useful and bind them to particular contexts.

Having done this for a while in code, I am somewhat convinced it is a useful model. Mind you, Erlang *does* have identity on its processes and it *does* support thread-local-storage (it's called the process dictionary), but using these is usually shunned upon, for good reason.


--
J.

Damian Turczyński

unread,
Feb 24, 2016, 3:07:50 PM2/24/16
to Jesper Louis Andersen, golang-nuts
Jesper, thank you for your respond. Indeed I've found gls solution, but it's also not very neat as it requires changing go calls to package function call. It also use very 'hacky' way of getting that identifier.

I agree with you that extensive usage of thread memory is dangerous and not wise. I was only planning to use it for logging purposes not for storing some vital or fragile information.

Also I don't get all your return/error talk. I agree with everything what you are saying but it doesn't apply to any of my code. I don't use logging for error handling. I just want to differentiate logs per request as those are happening concurrently. Also I'm mostly speaking of Info logs and not about error logs.

My ideology is to not repeat myself and if even language's creators suggesting me to pass one object to every (sic!) single function call I really don't see a point... And yes I need to have possibility of logging every single operation I'm doing everywhere in the program.
--
Damian Turczyński

Jesper Louis Andersen

unread,
Feb 24, 2016, 3:17:44 PM2/24/16
to Damian Turczyński, golang-nuts

On Wed, Feb 24, 2016 at 9:07 PM, Damian Turczyński <dam...@gmail.com> wrote:
Also I'm mostly speaking of Info logs and not about error logs.

Ah, I have another approach for those entirely in most of the code I write. Logging is, relatively speaking, expensive. So in order to show progress I often have a separate system in the applications for monitoring purposes where I record not the line entry itself but counts/gauges/histograms/spirals/decay-filters and so on. I rarely track the individual request in this case but aggregate them into more general counters, store them temporarily in memory, and then ship them to monitoring systems for statistical analysis.

If I'm interested in particular requests, I often use tracing (think either dtrace(1) or the tracing facilities of the Erlang VM). I'm sure Go has a number of useful tools for ad-hoc tracing of what goes on inside the system. The reason I prefer tracing over logging is the simple observation that bugs often happen in the places you have no log statement: the ones which had logging are already weeded out.


--
J.

Dan Kortschak

unread,
Feb 24, 2016, 5:24:36 PM2/24/16
to Damian Turczyński, Jesper Louis Andersen, golang-nuts
This is another hacky way to do it.

http://play.golang.org/p/OeEmT_CXyO

Mike Atlas

unread,
May 6, 2016, 5:58:33 PM5/6/16
to golang-nuts, dam...@gmail.com, jesper.lou...@gmail.com
@kortschak, hacky or not, I found your snippit useful in walking through a goroutine race condition bug on a mutux. Thank you. I ended up leaving it with a conditional call only if in logging Debug mode, otherwise it doesn't get called. Tracked down my problem right away, and will leave the code where it is thanks to wrapping it in the logging debug conditional.

-Mike

eric.h...@newcontext.com

unread,
Apr 26, 2017, 6:05:48 PM4/26/17
to golang-nuts, dam...@gmail.com, jesper.lou...@gmail.com
I agree. its great to actively discourage thread local state.

but I'm in the same position, debugging a concurrency problem with 3rd party libraries, have a case where it never happens, and a case where it always happens.

so this would help me verify my assumptions and track down whats going on

ala...@dotmesh.com

unread,
Jun 15, 2018, 9:59:42 AM6/15/18
to golang-nuts
I agree the OP possibly doesn't want thread-local storage (although I'd like to point out that Scheme's dynamically-scoped "parameters" are a great way to do what the OP wants!), but I'll post another use case where thread IDs of some kind are useful: I work on highly concurrent software, and it's very useful to be able to dump all the goroutines in such a system and see what they're doing. Sure, we've got the pprof goroutine profile, but that gives limited information - I have many goroutines using a polling function that calls a func, then sleeps, then loops forever. So, in most goroutine profiles, I see that goroutine in a sleep rather than in its polling function, and so can't tell what the purpose of that goroutine is (despite it having a string named in its stack frame, used when printing an error returned from the func). It'd be nice if I could record a mapping from the "goroutine ID" of these, and similar, goroutines to arbitrary "what this goroutine is for" strings that I could look up in my dump. In Java, every thread has a name field, which I (ab)used for this purpose to great effect!

Ian Lance Taylor

unread,
Jun 15, 2018, 10:23:55 AM6/15/18
to ala...@dotmesh.com, golang-nuts
On Fri, Jun 15, 2018 at 2:20 AM, <ala...@dotmesh.com> wrote:
>
> I agree the OP possibly doesn't want thread-local storage (although I'd like
> to point out that Scheme's dynamically-scoped "parameters" are a great way
> to do what the OP wants!), but I'll post another use case where thread IDs
> of some kind are useful: I work on highly concurrent software, and it's very
> useful to be able to dump all the goroutines in such a system and see what
> they're doing. Sure, we've got the pprof goroutine profile, but that gives
> limited information - I have many goroutines using a polling function that
> calls a func, then sleeps, then loops forever. So, in most goroutine
> profiles, I see that goroutine in a sleep rather than in its polling
> function, and so can't tell what the purpose of that goroutine is (despite
> it having a string named in its stack frame, used when printing an error
> returned from the func). It'd be nice if I could record a mapping from the
> "goroutine ID" of these, and similar, goroutines to arbitrary "what this
> goroutine is for" strings that I could look up in my dump. In Java, every
> thread has a name field, which I (ab)used for this purpose to great effect!

You should look into https://golang.org/pkg/runtime/pprof/#Do, which
provides a mechanism for labeling a goroutine in a way that pprof can
display.

Ian

Tang Shiwei

unread,
Oct 30, 2018, 12:18:27 AM10/30/18
to golang-nuts


Now i have the same problem as you, i need to record log id through a web request, and pass the log id by httpContext, its look orderless for my code, so sad!

robert engels

unread,
Oct 30, 2018, 12:34:06 AM10/30/18
to Tang Shiwei, golang-nuts
I agree. I’ve read the arguments against thread-local (or goroutine local storage), and the passing of Context everywhere instead. It doesn’t make sense to me.

Even a simple runtime.GetGoID() that returned a unique int would allow the design of much simpler server software.

But I don’t think it is going to change, so get to know ‘refactor method signature in IntelliJ’ really well.

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Max

unread,
Oct 30, 2018, 5:13:06 AM10/30/18
to golang-nuts
I agree on the fact that passing a Context everywhere is impossible in some cases - just think about the many APIs (from standard library and 3rd parties) that do not accept a Context - and in some other cases very complicated, requiring extensive refactoring.

I also agree with the recommendation to DO pass a Context when feasible. It's just that sometimes it's not feasible, and infact in my case (a Go interpreter) I was forced to resort to goroutine-local storage as the only possible solution.

If you are interested, you can have a look at my fast (one line of assembly) implementation: https://github.com/cosmos72/gls
Reply all
Reply to author
Forward
0 new messages