返回信息流go社区反对goroutine局部变量,可能是跟gc有关系,所以干脆连goroutine id也不给你
但是打印日志没有goroutine太难查问题了,看了下go代码,把goroutine id偷出来了,实际上是个管理结构的内存地址
只写了x86_64平台的,1.5/1.6可用
asm_amd64.s文件:
TEXT s3lib·GoID(SB),$0-8
MOVQ TLS, CX
MOVQ 0(CX)(TLS*1), AX
MOVQ AX, ret+0(FP)
RET
go文件:
func GoID() int64
这是一条镜像帖。来源:北邮人论坛 / golang / #296同步于 2016/6/15
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Golang机器人发帖
分享个偷goroutine id的黑科技
KajiRyouji
2016/6/15镜像同步7 回复
订阅后,新回复会通过你的通知中心匿名送达。
7 条回复
这是实现细节,肯定不会可靠。
thread-local storage这个东西本来就需要慎用。最最难的地方在于:定义了新的thread-local变量(可能会因为动态装载别的库而引入新的thread-local),但现有的线程(goroutine)的thread-local storage应当如何扩容,以容纳新的变量?
最可靠的还是编程语言自身规定一些thread-local变量,仅仅用于某些特殊的目的(比如x10的finish-async栈,又比如垃圾回收器的local内存池)
能说下什么样的问题需要查gotoutine吗?谢谢。
【 在 KajiRyouji 的大作中提到: 】
: go社区反对goroutine局部变量,可能是跟gc有关系,所以干脆连goroutine id也不给你
: 但是打印日志没有goroutine太难查问题了,看了下go代码,把goroutine id偷出来了,实际上是个管理结构的内存地址
: 只写了x86_64平台的,1.5/1.6可用
: ...................
每个goroutine处理一个请求,中间会打印若干条日志,如果没有goroutine id标记的话,很难把一次请求的多条日志串起来看
【 在 shmilyhx 的大作中提到: 】
: 能说下什么样的问题需要查gotoutine吗?谢谢。
:
【 在 KajiRyouji 的大作中提到: 】
: 每个goroutine处理一个请求,中间会打印若干条日志,如果没有goroutine id标记的话,很难把一次请求的多条日志串起来看
:
这种情况 难道一般不都是给每个请求一个ID吗。。
http://stackoverflow.com/questions/31932945/does-go-have-something-like-threadlocal-from-java
这个应该可以看出Go开发人员的态度:goroutine很便宜,但不希望用户创建TLS。
从语言实现人员的角度看,TLS需要很高的技巧才能实现,所以应该用在语言本身的关键部位,而不是给用户自定义。
但是,如果连最基本的标识符都不提供,就是语言的不对了。Java有`java.lang.ThreadLocal<T>`,是用`HashMap<Thread, T>`实现的,效率很低;但每个线程可以有一个name,这个name可以用寄存器相对寻址来实现,效率并不会很低,而且也算是语言自带的功能。这个name对打印日志提供了很大的帮助。
所以说,如果让我评价,我认为这是go语言的错。go做得太极端了。可以不给用户自定义TLS的权利,但不应连一个ID都不给。
【 在 KajiRyouji 的大作中提到: 】
: 没法做到层层接口都传id,还有第三方库呢
:
对。TLS解决的正是这种问题。具体一点,就是每个函数都是为不同的目的而实现的,不能要求所有的函数都多带一个额外的参数,因为这些函数即使么有那个额外参数照样工作。
但是,我还是觉得,如果一个程序本身就是为多线程实现的,那么那些和线程本身相关的逻辑应该都已经被放到一个和线程相关的类里面了才对(Go没有类,但应该有类似的)。
比如,如果我用Java写一个程序,我会这样写:
```java
class MyJob extends Runnable {
private String name;
private T blahblah;
public MyJob(String name, T blahblah) {
this.name = name; this.blahblah=blahblah;
}
@Override
public void run() {
doFoo(); doBar();
}
private void doFoo() {
logger.info("Job {0} is doing foo to blahblah...", name);
blahblah.read();
}
private void doBar() {
logger.info("Job {0} is doing bar to blahblah...", name);
blahblah.write();
doBaz();
}
private void doBaz() {
logger.info("Job {0} is doing baz to blahblah...", name);
blahblah.delete();
}
}
```
这样,所有和这个MyJob有关的数据都在MyJob类里,所有的方法都可以通过成员来访问。
如果某个组件不是为多线程设计的,它就不需要访问MyJob的成员,但仍然是可以工作的。
但是,可能日志是一个极大的特例。日志信息应该分线程记录,但那些需要写日志的组件可能完全不是为多线程设计的。
还有一些特例,比如x10风格的finish-async,也需要一个TLS来维护一个栈。