刚刚接触 go 语言,想请问一个问题,go routine 是如何在后台可以完成耗时的任务而不阻塞当前的任务的呢?
像 python 的 Tornado 可以使用 Thread.Exector 来进行调度,等这个协程跑完之后可以切换到新建的线程池中来进行耗时的操作的处理,也可以使用 asyncio 里面,先把协程任务跑完,然后在最后的事件循环中添加任务来让耗时任务运行。
求 go 语言的高手们解答一下。
1
ryd994 2017-10-31 23:38:34 +08:00 via Android
举个例子,对于 socket,用 select
你自己写 select 也是一个效果,但是 go 把这个机制做到运行环境里,再用语法糖使得这个流程就像线程一样易于理解和开发 你可以看看这个视频 |
2
changwei 2017-11-01 02:56:41 +08:00 via Android
你说的那种如何实现就得看 go 源码了。
传统的 c 语言,python,创建线程要经历 new threadclass,start 等操作,并且 c 语言下还需要进行函数参数的结构体封装,python 因为有 gil 锁,导致其线程无法充分利用多核 cpu。 而 go 创建线程(实际上是 goroutine 协程)只需要在函数前面加一个 go 关键词,并且底层运行时环境会自动根据系统 cpu 核心来调度 goroutine,不存在线程创建过多之后带来线程切换的性能损失。把并发程序的开发简化了很多。 |
3
halfer53 2017-11-01 03:36:37 +08:00 via Android 1
go 自身有一个调度器,当其中一个协程调用 blocking syscall,比如 read,go 的调度器回自动检测到,并把同一 socket 下的其他协程切换到其他 socket 去。等 syscall 完成以后,再恢复原状
|
4
halfer53 2017-11-01 03:37:55 +08:00 via Android
我说的 socket 指的是多核 cpu 下的每一个核
|
5
janxin 2017-11-01 07:26:12 +08:00 via iPhone
lz 是否只用过 python 或者只了解过 python 的并发编程?建议从几种常见的并发编程模型入手更容易理解
|
6
araraloren 2017-11-01 09:00:19 +08:00
建议你看看这一篇文章,那得根据耗时的任务类型区别对待。。
https://studygolang.com/articles/2357 |
7
ray1888 OP @janxin 因为 python 会用得比较多,以前大学学的 java 和 c++都太久没用,所以现在思路主要是以 python 为主
|
9
ZSeptember 2017-11-01 09:47:17 +08:00
你看操作系统怎么同时完成多个任务的,当然在微观上同时执行的只有几个任务。
Go 就是这样实现的,Go 的 runtime 实现了一个类似于操作系统的调度器,然后编译器在在函数调用或者什么其他的地方插入一下检查函数,如果 go routine 执行时间过长,就抢占了,执行其他任务 IO 最终都会是系统调用,在系统调用的入口处理一下,就可以使用系统提供的 epoll 之类的了 |
12
zts1993 2017-11-01 09:52:27 +08:00
主要两种
io 类自动转为 non-blocking,epoll trigger 之后恢复 context,继续执行之前的 goroutine syscall 类的,超时之后会吧队列中其他待执行的移到另一个新 thread 中运行。 可以了解一下 golang M P G |
13
HarrisonZ 2017-11-01 14:03:38 +08:00
golang 官网的文档先看看吧
|