1
darklowly 2014-03-11 14:46:18 +08:00 via iPhone
为什么不直接用go
|
2
seeker 2014-03-11 14:48:37 +08:00
刚搜了下搜到这个,给撸主参考参考: http://luvit.io/
|
3
mingzhi 2014-03-11 14:50:44 +08:00
lz 说的是这货 http://luvit.io/ 这样?
|
4
ryanking8215 OP golang也是同步的啊
我靠,真有这玩意儿,还说比node.js快2~4倍。 |
5
initialdp 2014-03-11 15:19:40 +08:00
国内云风开源的skynet据说也是杠杠的。
|
6
clino 2014-03-11 15:35:06 +08:00 1
用lua当然要用coroutine了,为什么还用event loop这种编程界面这么恶心的东东呢
|
7
ryanking8215 OP 我不觉得event loop很恶心啊,嵌入式上一直用libevent。
最近觉得多线程会造成心智负担,担心死锁的问题。包括goroutine。 callback嵌套多点就多点吧,不是还有async,eventproxy么?至少我知道cpu在执行这里的时候,别的代码对这个没影响。难道是年纪大了? |
8
alsotang 2014-03-11 16:02:02 +08:00
反正 nodejs 的嵌套很恶心就对了。
|
9
kran 2014-03-11 16:03:19 +08:00
openresty, alilua ?
|
10
clino 2014-03-11 17:02:37 +08:00
@ryanking8215 如果用同步的方式写会有死锁,那么用eventloop方式一样会有吧
|
11
superhack 2014-03-11 20:09:52 +08:00
openresty 中的 ngx_lua
|
12
ryanking8215 OP @clino 用了单进程单线程的eventloop,那就不用锁了,就不会有死锁了。死锁不是因为同步写的原因,是因为要并发,临界区资源需要互斥,有资源需要同步访问,也有可能多个任务需要协调同步等等,就有锁的问题,一不小心就会死锁,其实死锁还好,万一临界区资源被无故改写,这个问题很难查,很难重现。
|
13
suninus 2014-03-11 20:55:52 +08:00 via Android
这个点个赞,@seeker真搜度
|
14
clino 2014-03-11 21:28:35 +08:00
@ryanking8215 coroutine 一样可以是单进程单线程来并发,照你这么说也不用锁
|
16
ryanking8215 OP @clino 你指lua的coroutine吗?lua不是很熟悉,但我记得是没有锁啊
|
17
clino 2014-03-12 10:04:18 +08:00
@ryanking8215 coroutine在几种语言的实现都是单线程里并发的,照你说都不用有锁了
另外event loop就不用锁了吗?你确定吗? |
18
ryanking8215 OP @clino 单线程单进程的event loop不需要锁,我确定。你说几种语言的coroutine的,我不是了解很多语言,单从lua讲,是单线程内执行的协程,不需要锁。 至于goroutine,是多线程支撑的CSP模型,需要锁的,它也提供的sync.Mutex,sync.Atomic,当然它提供更方便的chan是另一说了
|
19
clino 2014-03-12 10:46:14 +08:00
@ryanking8215 gevent是单线程的,它一样提供锁的工具( http://xlambda.com/gevent-tutorial/#_11 ),可以用来"限制并发访问或运行",当然也可以不用
不过 event loop 确实就没办法用了,所以在这点上也能看出这种编程接口没coroutine灵活 至于goroutine,你要想做成单线程一样也可以,这是使用者的选择,不一定非要用多线程的方式 |
20
ryanking8215 OP @clino 我看了一下gevent,我同意你的说法。我的理解是从资源保护上讲,是不需要锁的,因为gevent的cpu是用户显示释放的,不是OS调度的,没有临界区的问题,但是你要同步gevent,控制gevent的执行顺序,就需要信号量和锁了。
但是你说的关于goroutine的,我不太认同,goroutine是go runtime的调度器调度的,什么时候切换goroutine是自动的,不是用户控制的,如果没有互斥和同步原语,我觉得是有临界区问题的。我不清楚如何起n个gorouine是保证在一个线程上的。 |
21
clino 2014-03-12 12:48:21 +08:00
@ryanking8215 你保证是在一个线程里使用 goroutine 不就可以保证这个线程里的goroutine不会并行执行了嘛
用不用多线程或者多进程难道你不能决定吗? |
22
ryanking8215 OP @clino goroutine和lua的coroutine还有gevent等这种协程是不同的概念。
协程生成在哪个线程上,就在哪个线程进行上下文切换, 但在golang里没有线程的概念,goroutine的这种设计屏蔽了操作系统的线程,目前的并发是使用线程来实现的,m个goroutine跑在n个线程上(m>=n),当你起goroutine时,golang的调度器负责将goroutie分配给已有线程或者新建线程。 你可以安装golang跑个例子看看 |
23
clino 2014-03-12 13:41:39 +08:00
@ryanking8215 我对go确实不了解,但刚才搜了一下应该也是可以配置的,而且应该是默认为单线程
http://blog.chinaunix.net/uid-22312037-id-3760407.html " 默认情况下,调度器仅适用单线程,也就是说只实现了并发。想要发挥多核处理器的并行,需要在程序中显示调用runtime.GOMAXPROCS(n)告诉调度器同时使用多个线程。GOMAXPROCS设置了同时运行逻辑代码的系统线程的最大数量,并返回之前的设置。如果n<1,不会改变当前设置。关于并发和并行请参看rob的这篇文章" |
24
ryanking8215 OP @clino http://golang.org/pkg/runtime/#GOMAXPROCS, 是设置多少个cpu参与并行,而不是线程数。
这篇东西完全在误导! 我刚才试了了一下: func main() { <- time.After(5*time.Minute) } 简单的定时器,golang帮我开了5个线程,包括主线程,通过ls /proc/<pid>/task/查看 |
25
clino 2014-03-12 14:52:54 +08:00
@ryanking8215 看起来我给的这篇是不靠谱,goroutine确实和coroutine差别比较大,我之前想当然了
我想弄个go来试试,不过到现在没下载完 又搜到一篇: http://xiezhenye.com/2012/08/%e5%86%8d%e6%8e%a2-goroutine.html "goroutine 并不是像我之前认为的,在 cgocall 或者 syscall 的时候进行自动切换,而是使用了线程。同时,这个线程数和 runtime.GOMAXPROCS 也没有直接关联。在这个情况下,虽然 runtime.GOMAXPROCS 设为了 2 ,但是最后照样用了 1000 多个线程。但是 strace -f ./par 直接运行,此时跟踪线程数,最多就只有几十个。看来和 less 也有关系" "go 语言要避免大量线程产生的切换开销,用类似 coroutine 的方式,还是得结合异步 io 。但是目前只在网络 io 上实现了这点。对于其他的 io,比如文件系统,仍然会由于阻塞而产生线程。如果应用中需要使用文件 io,就得使用生产者消费者模式来减少线程数量,或者可以考虑利用 netfd 的代码来实现一个其他类型 io 的异步包装(当然功能上会有一些限制)" |
26
ryanking8215 OP @clino 他说的是对的,第一段的“同时,这个线程数和 runtime.GOMAXPROCS 也没有直接关联。在这个情况下,虽然 runtime.GOMAXPROCS 设为了 2 ,但是最后照样用了 1000 多个线程。”,这句话没错,但是本来这2个就没有关系,并发和并行是2个概念,一个cpu可以通过开启n多个线程/进程并发或使用多个协程并发或使用event_loop并发,但不是并行计算,因为只有一个cpu,多个cpu参与就可以并行计算,多线程/多进程模型可以支持并行,但协程和event_loop就不支持了。
第二段说的包装io,libuv就封装了异步的io,是通过线程来实现的,毕竟filesystem io是block的。 goroutine把并发和并行结合了起来,而且不造成过多负担,模型一致。 我这样理解的并发(cocurrency)和并行(parallel):并发是逻辑上的“并发”,并行是物理上的“并发”。 |
27
clino 2014-03-12 16:13:16 +08:00
@ryanking8215 感觉很奇怪
如下代码,如果是只有一个go func() ,我这里是4个线程,如果有3个 go func(),则变成3个线程 不知道go内部是啥逻辑 func main() { runtime.GOMAXPROCS(1) go func() { time.Sleep(3*time.Second) fmt.Println("Hello, World. after 3 seconds") }() go func() { time.Sleep(4*time.Second) fmt.Println("Hello, World. after 4 seconds") }() go func() { time.Sleep(5*time.Second) fmt.Println("Hello, World. after 5 seconds") }() time.Sleep(6*time.Second) fmt.Println("end") } |
28
ryanking8215 OP 这个是golang的调度器实现的,具体的我也不懂了,没研究过。
|