说点我对goroutine的看法
传统多线程程序
Thread1
Do-something
Do-something-block
....
在thread1 block之后,如果还想要干其他事情,
那就只有再开一个thread来做事了
这样一来,当线程足够多时,性能就会下降,这是显然的
于是就有了非阻塞式/异步 比如epoll
Thread1
Do-something
Do-something-unblock-with-callback
...
ThreadN
Callback
Do-somehting
也即将原来可能阻塞的地方的代码以回调,事件等方式分解,在别的时候当条件满足时再执行。
这样就可以利用为数不多的线程来高效的完成任务。
但是显然这种方式,写起来很费劲,读起来很费劲,调试起来也很费劲。
而go语言利用goroutine来解决了这一点,goroutine替代原来的thread成了最小调度单元,
一旦goroutine中的某个函数比如网络读写,或者sleep函数阻塞时,goroutine被挂起,
当前执行goroutine的线程可以再去找一个需要执行的goroutine去执行它,如果没找到,好吧,那就是死锁了。
其实goroutine的设计跟asio是很像的,毕竟都是基于CSP模型的,只不过它直接在语言层面实现的,使得代码看起来更加清晰,直观。
对我而言go语言最有魅力的地方就是goroutine这里了。上面是一些个人理解,如果有不对的,还请大家指正。
一旦goroutine中的某个函数比如网络读写,或者sleep函数阻塞时,goroutine被挂起,
当前执行goroutine的线程可以再去找一个需要执行的goroutine去执行它
嗯,谢谢瑞琦,这里说错了,Proc.c里确实是这样做的。
补充一点,创建新线程不是无限限制的,而有一个上限的,如果当前的线程数达到上限
那么goroutine就进入等待队列了。
目前对于网络层的阻塞操作实际上似乎是将goroutine挂起的,将当前thread标志来空闲,然后等待epoll来重新调度的。
我不知道其他的系统调用是不是有直接阻塞的?
发件人: golang...@googlegroups.com [mailto:golang...@googlegroups.com] 代表 洪瑞琦
发送时间: 2012年2月3日 16:13
收件人: golang...@googlegroups.com
主题: Re: [gocn:2042] 谈点对goroutine的理解
一旦goroutine中的某个函数比如网络读写,或者sleep函数阻塞时,goroutine被挂起,
当前执行goroutine的线程可以再去找一个需要执行的goroutine去执行它
实际的情况是,当前线程阻塞时,其它的goroutine并不是在当前线程执行的,而是被分配到空闲的线程(阻塞不是空闲),如果没有空闲线程就新建一个。新建线程中的goroutine执行完毕后,线程不会退出,成为空闲线程(一个动态增加的线程池)
--
来自: Golang-China ~ 中文Go语言技术邮件列表
发言: golang...@googlegroups.com
详情: http://groups.google.com/group/golang-china
官网: http://golang-china.org/
翻译: http://github.com/border/golang-china/
论坛: http://bbs.golang-china.org/
@golangchina
func GOMAXPROCS(n int) int
GOMAXPROCS sets the maximum number of CPUs that can be executing simultaneously and returns the previous setting. If n < 1, it does not change the current setting. The number of logical CPUs on the local machine can be queried with NumCPU. This call will go away when the scheduler improves.
另外可以参考proc.c里的atomic
// The atomic word in sched is an atomic uint32 that
// holds these fields.
//
// [15 bits] mcpu number of m's executing on cpu
// [15 bits] mcpumax max number of m's allowed on cpu
// [1 bit] waitstop some g is waiting on stopped
// [1 bit] gwaiting gwait != 0
发件人: golang...@googlegroups.com [mailto:golang...@googlegroups.com] 代表
洪瑞琦
发送时间: 2012年2月3日 16:35
收件人: golang...@googlegroups.com
主题: Re: 答复: [gocn:2044] 谈点对goroutine的理解
应该确实是最大同时执行的thread数,但是这里有个问题,当执行syscall时,当前的线程是什么状态?它可以转让出去给其他goroutine使用吗?
发件人: golang...@googlegroups.com [mailto:golang...@googlegroups.com] 代表
洪瑞琦
发送时间: 2012年2月3日 17:21
收件人: golang...@googlegroups.com
主题: Re: 答复: 答复: [gocn:2046] 谈点对goroutine的理解
多谢,汇编已经看不懂了,许多地方靠猜了,继续再看看runtime
发件人: golang...@googlegroups.com [mailto:golang...@googlegroups.com] 代表
洪瑞琦
发送时间: 2012年2月3日 19:13
收件人: golang...@googlegroups.com
主题: Re: 答复: 答复: 答复: [gocn:2051] 谈点对goroutine的理解
对了,例如像fmt.Println()这样的调用应该是系统调用吧?
因此如果当前线程有fmt.Println(),则会被阻塞,然后Go的运行时会试着在其他线程中运行可运行的goroutine(如果有的话)?
另外,由于发生fmt.Println()而被阻塞的线程,什么时候会被重新调用?Go的运行时如何知道这个线程可以被重新调用,而不是继续阻塞?
谢谢!
--
Yili Zhao
OTһ�£��ܷ���"��"������Re:����RE:������ʱ�������?
> *������:*golang...@googlegroups.com
> [mailto:golang...@googlegroups.com] *��� *������
> *����ʱ��:*2012��2��3��19:13
> *�ռ���:*golang...@googlegroups.com
> *����:*Re: ��: ��: ��: [gocn:2051] ̸���goroutine�����
>
> IO��ص�Syscall����ִ�е��ȣ��ѿ����е�goroutine�ŵ������߳����У�ͬʱ��
> �е�<=GOMAXPROC����Ȼ��ǰ�߳�����
>
> �����Syscall��ֱ������ǰ�߳�
>
> ��2012��2��3�� ����6:54��Hoping White <baiha...@gmail.com
> <mailto:baiha...@gmail.com>>���
>
> Ӧ��ȷʵ�����ͬʱִ�е�thread���������и����⣬��ִ��syscallʱ����
> ǰ���߳���ʲô״̬�������ת�ó�ȥ������goroutineʹ����
>
> *������:*golang...@googlegroups.com
> <mailto:golang...@googlegroups.com>
> [mailto:golang...@googlegroups.com
> <mailto:golang...@googlegroups.com>] *��� *
>
> ������
> *����ʱ��:*2012��2��3��17:21
> *�ռ���:*golang...@googlegroups.com
> <mailto:golang...@googlegroups.com>
> *����:*Re: ��: ��: [gocn:2046] ̸���goroutine�����
>
> ���˼����ط���û�����������
>
> GOMAXPROC��mcpumax���������ƵĻ�߳�������߳���
>
> ��2012��2��3�� ����5:12��Hoping White <baiha...@gmail.com
> <mailto:baiha...@gmail.com>>���
>
> func GOMAXPROCS(n int) int
>
> GOMAXPROCS sets the maximum number of CPUs that can be executing
> simultaneously and returns the previous setting. If n < 1, it does not
> change the current setting. The number of logical CPUs on the local
> machine can be queried with NumCPU. This call will go away when the
> scheduler improves.
>
> ������Բο�proc.c���atomic
>
> // The atomic word in sched is an atomic uint32 that
>
> // holds these fields.
>
> //
>
> // [15 bits] mcpu number of m's executing on cpu
>
> // [15 bits] mcpumax max number of m's allowed on cpu
>
> // [1 bit] waitstop some g is waiting on stopped
>
> // [1 bit] gwaiting gwait != 0
>
> *������:*golang...@googlegroups.com
> <mailto:golang...@googlegroups.com>
> [mailto:golang...@googlegroups.com
> <mailto:golang...@googlegroups.com>] *��� *
>
> ������
> *����ʱ��:*2012��2��3��16:35
> *�ռ���:*golang...@googlegroups.com
> <mailto:golang...@googlegroups.com>
> *����:*Re: ��: [gocn:2044] ̸���goroutine�����
>
>
> ����߳�����û��ע�⣬�����ϵͳ���Ƶģ�������go�������Ƶģ�Ĭ���Ƕ���
> �أ�лл
>
> ��2012��2��3�� ����4:27��Hoping White <baiha...@gmail.com
> <mailto:baiha...@gmail.com>>���
>
> �ţ�лл��������˵���ˣ�Proc.c��ȷʵ���������ġ�
>
> ����һ�㣬�������̲߳����������Ƶģ�����һ�����ģ����ǰ���߳���ﵽ����
>
> ��ôgoroutine�ͽ���ȴ�����ˡ�
>
> Ŀǰ�����������������ʵ�����ƺ��ǽ�goroutine����ģ�����ǰthread��־
> �����У�Ȼ��ȴ�epoll�����µ��ȵġ�
>
> �Ҳ�֪�������ϵͳ�����Dz�����ֱ������ģ�
>
> *������:*golang...@googlegroups.com
> <mailto:golang...@googlegroups.com>
> [mailto:golang...@googlegroups.com
> <mailto:golang...@googlegroups.com>] *��� *������
> *����ʱ��:*2012��2��3��16:13
> *�ռ���:*golang...@googlegroups.com
> <mailto:golang...@googlegroups.com>
> *����:*Re: [gocn:2042] ̸���goroutine�����
>
> һ��goroutine�е�ij��������������д������sleep��������
> ʱ��goroutine������
>
> ��ǰִ��goroutine���߳̿�����ȥ��һ����Ҫִ�е�goroutineȥִ����
>
> ʵ�ʵ�����ǣ���ǰ�߳�����ʱ�������goroutine�������ڵ�ǰ�߳�ִ�еģ���
> �DZ����䵽���е��̣߳������ǿ��У������û�п����߳̾��½�һ�����½���
> ���е�goroutineִ����Ϻ��̲߳����˳�����Ϊ�����̣߳�һ����̬���ӵ���
> �̳أ�
>
> --
>
> ����: Golang-China ~ ����Go���Լ����ʼ��б�
> ����: golang...@googlegroups.com <mailto:golang...@googlegroups.com>
> ����: http://groups.google.com/group/golang-china
> ����: http://golang-china.org/
> ����: http://github.com/border/golang-china/
> ��̳: http://bbs.golang-china.org/
> @golangchina
>
> --
> ����: Golang-China ~ ����Go���Լ����ʼ��б�
> ����: golang...@googlegroups.com <mailto:golang...@googlegroups.com>
> ����: http://groups.google.com/group/golang-china
> ����: http://golang-china.org/
> ����: http://github.com/border/golang-china/
> ��̳: http://bbs.golang-china.org/
> @golangchina
>
> --
> ����: Golang-China ~ ����Go���Լ����ʼ��б�
> ����: golang...@googlegroups.com <mailto:golang...@googlegroups.com>
> ����: http://groups.google.com/group/golang-china
> ����: http://golang-china.org/
> ����: http://github.com/border/golang-china/
> ��̳: http://bbs.golang-china.org/
> @golangchina
>
> --
> ����: Golang-China ~ ����Go���Լ����ʼ��б�
> ����: golang...@googlegroups.com <mailto:golang...@googlegroups.com>
> ����: http://groups.google.com/group/golang-china
> ����: http://golang-china.org/
> ����: http://github.com/border/golang-china/
> ��̳: http://bbs.golang-china.org/
> @golangchina
>
> --
> ����: Golang-China ~ ����Go���Լ����ʼ��б�
> ����: golang...@googlegroups.com <mailto:golang...@googlegroups.com>
> ����: http://groups.google.com/group/golang-china
> ����: http://golang-china.org/
> ����: http://github.com/border/golang-china/
> ��̳: http://bbs.golang-china.org/
> @golangchina
>
> --
> ����: Golang-China ~ ����Go���Լ����ʼ��б�
> ����: golang...@googlegroups.com <mailto:golang...@googlegroups.com>
> ����: http://groups.google.com/group/golang-china
> ����: http://golang-china.org/
> ����: http://github.com/border/golang-china/
> ��̳: http://bbs.golang-china.org/
> @golangchina
>
> --
> ����: Golang-China ~ ����Go���Լ����ʼ��б�
> ����: golang...@googlegroups.com <mailto:golang...@googlegroups.com>
> ����: http://groups.google.com/group/golang-china
> ����: http://golang-china.org/
> ����: http://github.com/border/golang-china/
> ��̳: http://bbs.golang-china.org/
> @golangchina
>
> --
> ����: Golang-China ~ ����Go���Լ����ʼ��б�
> ����: golang...@googlegroups.com
> ����: http://groups.google.com/group/golang-china
> ����: http://golang-china.org/
> ����: http://github.com/border/golang-china/
> ��̳: http://bbs.golang-china.org/
> @golangchina
Hoping White wrote, On 02/03/2012 06:33 AM:
> 多谢,汇编已经看不懂了,许多地方靠猜了,继续再看看runtime
>
OT一下,能否不用"答复",改用Re:或者RE:,方便时间线整理。
> *发件人:*golang...@googlegroups.com
> [mailto:golang...@googlegroups.com] *代表 *洪瑞琦
> *发送时间:*2012年2月3日19:13
> *收件人:*golang...@googlegroups.com
> *主题:*Re: 答复: 答复: 答复: [gocn:2051] 谈点对goroutine的理解
>
> IO相关的Syscall会先执行调度,把可运行的goroutine放到其它线程运行(同时运
> 行的<=GOMAXPROC),然后当前线程阻塞
>
> 其它的Syscall则直接阻塞当前线程
>
> 在2012年2月3日 下午6:54,Hoping White <baiha...@gmail.com
> <mailto:baiha...@gmail.com>>写道:
>> *发件人:*golang...@googlegroups.com
> 应该确实是最大同时执行的thread数,但是这里有个问题,当执行syscall时,当
> 前的线程是什么状态?它可以转让出去给其他goroutine使用吗?
>
> <mailto:golang...@googlegroups.com>
> [mailto:golang...@googlegroups.com
> <mailto:golang...@googlegroups.com>] *代表 *
>
> 洪瑞琦
> *发送时间:*2012年2月3日17:21
> *收件人:*golang...@googlegroups.com
> <mailto:golang...@googlegroups.com>
> *主题:*Re: 答复: 答复: [gocn:2046] 谈点对goroutine的理解
>
> 看了几个地方,没看完整就是了
>
> GOMAXPROC和mcpumax好像都是限制的活动线程数,并非总线程数
>
> 在2012年2月3日 下午5:12,Hoping White <baiha...@gmail.com
> <mailto:baiha...@gmail.com>>写道:
>
> func GOMAXPROCS(n int) int
>
> GOMAXPROCS sets the maximum number of CPUs that can be executing
> simultaneously and returns the previous setting. If n < 1, it does not
> change the current setting. The number of logical CPUs on the local
> machine can be queried with NumCPU. This call will go away when the
> scheduler improves.
>
> 另外可以参考proc.c里的atomic
>
> // The atomic word in sched is an atomic uint32 that
>
> // holds these fields.
>
> //
>
> // [15 bits] mcpu number of m's executing on cpu
>
> // [15 bits] mcpumax max number of m's allowed on cpu
>
> // [1 bit] waitstop some g is waiting on stopped
>
> // [1 bit] gwaiting gwait != 0
>
> *发件人:*golang...@googlegroups.com
> <mailto:golang...@googlegroups.com>
> [mailto:golang...@googlegroups.com
> <mailto:golang...@googlegroups.com>] *代表 *
>
> 洪瑞琦
> *发送时间:*2012年2月3日16:35
> *收件人:*golang...@googlegroups.com
> <mailto:golang...@googlegroups.com>
> *主题:*Re: 答复: [gocn:2044] 谈点对goroutine的理解
>
>
> 最大线程数倒是没有注意,这个是系统限制的,还是由go自身限制的?默认是多少
> 呢?谢谢
>
> 在2012年2月3日 下午4:27,Hoping White <baiha...@gmail.com> <mailto:baiha...@gmail.com>>写道:
>
> 嗯,谢谢瑞琦,这里说错了,Proc.c里确实是这样做的。
>
> 补充一点,创建新线程不是无限限制的,而有一个上限的,如果当前的线程数达到上限
>
> 那么goroutine就进入等待队列了。
>
> 目前对于网络层的阻塞操作实际上似乎是将goroutine挂起的,将当前thread标志
> 来空闲,然后等待epoll来重新调度的。
>
> 我不知道其他的系统调用是不是有直接阻塞的?
>
> *发件人:*golang...@googlegroups.com
> <mailto:golang...@googlegroups.com>
> [mailto:golang...@googlegroups.com
> <mailto:golang...@googlegroups.com>] *代表 *洪瑞琦
> *发送时间:*2012年2月3日16:13
> *收件人:*golang...@googlegroups.com
> <mailto:golang...@googlegroups.com>
> *主题:*Re: [gocn:2042] 谈点对goroutine的理解
>
> 一旦goroutine中的某个函数比如网络读写,或者sleep函数阻塞
> 时,goroutine被挂起,
>
> 当前执行goroutine的线程可以再去找一个需要执行的goroutine去执行它
>
> 实际的情况是,当前线程阻塞时,其它的goroutine并不是在当前线程执行的,而
> 是被分配到空闲的线程(阻塞不是空闲),如果没有空闲线程就新建一个。新建线
> 程中的goroutine执行完毕后,线程不会退出,成为空闲线程(一个动态增加的线
> 程池)
>
> --
>
> 来自: Golang-China ~ 中文Go语言技术邮件列表
> 发言: golang...@googlegroups.com <mailto:golang...@googlegroups.com>
> 详情: http://groups.google.com/group/golang-china
> 官网: http://golang-china.org/
> 翻译: http://github.com/border/golang-china/
> 论坛: http://bbs.golang-china.org/
> @golangchina
>
> --
> 来自: Golang-China ~ 中文Go语言技术邮件列表
> 发言: golang...@googlegroups.com <mailto:golang...@googlegroups.com>
> 详情: http://groups.google.com/group/golang-china
> 官网: http://golang-china.org/
> 翻译: http://github.com/border/golang-china/
> 论坛: http://bbs.golang-china.org/
> @golangchina
>
> --
> 来自: Golang-China ~ 中文Go语言技术邮件列表
> 发言: golang...@googlegroups.com <mailto:golang...@googlegroups.com>
> 详情: http://groups.google.com/group/golang-china
> 官网: http://golang-china.org/
> 翻译: http://github.com/border/golang-china/
> 论坛: http://bbs.golang-china.org/
> @golangchina
>
> --
> 来自: Golang-China ~ 中文Go语言技术邮件列表
> 发言: golang...@googlegroups.com <mailto:golang...@googlegroups.com>
> 详情: http://groups.google.com/group/golang-china
> 官网: http://golang-china.org/
> 翻译: http://github.com/border/golang-china/
> 论坛: http://bbs.golang-china.org/
> @golangchina
>
> --
> 来自: Golang-China ~ 中文Go语言技术邮件列表
> 发言: golang...@googlegroups.com <mailto:golang...@googlegroups.com>
> 详情: http://groups.google.com/group/golang-china
> 官网: http://golang-china.org/
> 翻译: http://github.com/border/golang-china/
> 论坛: http://bbs.golang-china.org/
> @golangchina
>
> --
> 来自: Golang-China ~ 中文Go语言技术邮件列表
> 发言: golang...@googlegroups.com <mailto:golang...@googlegroups.com>
> 详情: http://groups.google.com/group/golang-china
> 官网: http://golang-china.org/
> 翻译: http://github.com/border/golang-china/
> 论坛: http://bbs.golang-china.org/
> @golangchina
>
> --
> 来自: Golang-China ~ 中文Go语言技术邮件列表
> 发言: golang...@googlegroups.com <mailto:golang...@googlegroups.com>
go程的调度直觉上想来,应该是round-robin的。一个go程阻塞了,另一个go程就起来了。这样一个线程就可以带很多go程了。至于调度的时候有没有优先级,还真的得好好考虑考虑。酱紫的话,go程不能太大,否则占用系统太久的话,响应就会是一个问题了。
另外,对于线程,事实已经证明,线程数量不能超core number太多,否则性能会受比较大影响。而且,thread里面的critical
section,很影响应用的整体性能。利用类CSP的go程,很大程度上可以把一些原来不得不用critical
section描述的东西转化成系统通讯,这是go最大的魅力所在。
当然,具体细化下去的话,问题还多多:
- go程的优化会不会做确定性的线程分配。比如gofunc1一定在线程1上,gofunc2一定在线程2上啥的。
- 有哪些事件可以作为go程阻塞的标志?等待别的go程的结果?I/O?memory access?有具体的列表吗?
只是,这么一种靠系统这么近的类CSP语言的发展,极大的方便了快速开发,真的是个写backend的无敌利器。
有空一定要仔细读读runtime pkg里面的code。
Best Regards,
Xiaofeng
2012/2/3 洪瑞琦 <hong...@gmail.com>:
作为go语言普通使用者,没有必要关注语言底层实现。如果确实有兴趣关注,也对相关的底层系统技术比较熟悉,建议去阅读go语言编译器源代码,一切都不言自明。在各种前提都不具备的情况下,各种猜测性质的讨论都没有实际意义,徒增疑惑而已。
如果一个go routine一直在一个thread上运行,它性能切换的代价就是换寄存器(一般core都有寄存器cache,直接替换就可以) ,这个代价是很小的。但是如果GOMAXPROC>1的话,它就有可能被换到别的thread上运行,这时候换寄存器不可能用cache,只能在core间对拷,所以代价会大一些。
除了寄存器外,线程间不共享的东西(我也想不起来还有什么了),也需要copy,这也是系统负担。
你有相应的博客文吗?我看看确认一下。
2012/2/3 洪瑞琦 <hong...@gmail.com>: