V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
这是一个专门讨论 idea 的地方。

每个人的时间,资源是有限的,有的时候你或许能够想到很多 idea,但是由于现实的限制,却并不是所有的 idea 都能够成为现实。

那这个时候,不妨可以把那些 idea 分享出来,启发别人。
ryanking8215
V2EX  ›  奇思妙想

把 lua 和 event loop 结合起来,是不是比 js 更给力

  •  
  •   ryanking8215 · 2014-03-11 14:33:13 +08:00 · 8162 次点击
    这是一个创建于 3704 天前的主题,其中的信息可能已经有所发展或是发生改变。
    js把event loop融入了它的血液了。从语法上看,lua和js相像的地方很多,大不同的地方是,lua都是同步接口,但所幸lua的core很小,是不是把它改动一下,结合libuv,也做成一个lua-async的东东,在通过luajit,是不是比js更给力?

    当然,前后端大一统就没了。lua和c/c++结合比用v8简单太多了。

    欢迎大家吐槽!
    28 条回复    1970-01-01 08:00:00 +08:00
    darklowly
        1
    darklowly  
       2014-03-11 14:46:18 +08:00 via iPhone
    为什么不直接用go
    seeker
        2
    seeker  
       2014-03-11 14:48:37 +08:00
    刚搜了下搜到这个,给撸主参考参考: http://luvit.io/
    mingzhi
        3
    mingzhi  
       2014-03-11 14:50:44 +08:00
    lz 说的是这货 http://luvit.io/ 这样?
    ryanking8215
        4
    ryanking8215  
    OP
       2014-03-11 14:51:43 +08:00
    golang也是同步的啊

    我靠,真有这玩意儿,还说比node.js快2~4倍。
    initialdp
        5
    initialdp  
       2014-03-11 15:19:40 +08:00
    国内云风开源的skynet据说也是杠杠的。
    clino
        6
    clino  
       2014-03-11 15:35:06 +08:00   ❤️ 1
    用lua当然要用coroutine了,为什么还用event loop这种编程界面这么恶心的东东呢
    ryanking8215
        7
    ryanking8215  
    OP
       2014-03-11 15:54:52 +08:00
    我不觉得event loop很恶心啊,嵌入式上一直用libevent。
    最近觉得多线程会造成心智负担,担心死锁的问题。包括goroutine。
    callback嵌套多点就多点吧,不是还有async,eventproxy么?至少我知道cpu在执行这里的时候,别的代码对这个没影响。难道是年纪大了?
    alsotang
        8
    alsotang  
       2014-03-11 16:02:02 +08:00
    反正 nodejs 的嵌套很恶心就对了。
    kran
        9
    kran  
       2014-03-11 16:03:19 +08:00
    openresty, alilua ?
    clino
        10
    clino  
       2014-03-11 17:02:37 +08:00
    @ryanking8215 如果用同步的方式写会有死锁,那么用eventloop方式一样会有吧
    superhack
        11
    superhack  
       2014-03-11 20:09:52 +08:00
    openresty 中的 ngx_lua
    ryanking8215
        12
    ryanking8215  
    OP
       2014-03-11 20:54:42 +08:00
    @clino 用了单进程单线程的eventloop,那就不用锁了,就不会有死锁了。死锁不是因为同步写的原因,是因为要并发,临界区资源需要互斥,有资源需要同步访问,也有可能多个任务需要协调同步等等,就有锁的问题,一不小心就会死锁,其实死锁还好,万一临界区资源被无故改写,这个问题很难查,很难重现。
    suninus
        13
    suninus  
       2014-03-11 20:55:52 +08:00 via Android
    这个点个赞,@seeker真搜度
    clino
        14
    clino  
       2014-03-11 21:28:35 +08:00
    @ryanking8215 coroutine 一样可以是单进程单线程来并发,照你这么说也不用锁
    RIcter
        15
    RIcter  
       2014-03-11 21:33:33 +08:00
    @seeker 好眼熟,我们是不是在哪见过,bathome么。。不对。。
    ryanking8215
        16
    ryanking8215  
    OP
       2014-03-12 09:15:40 +08:00
    @clino 你指lua的coroutine吗?lua不是很熟悉,但我记得是没有锁啊
    clino
        17
    clino  
       2014-03-12 10:04:18 +08:00
    @ryanking8215 coroutine在几种语言的实现都是单线程里并发的,照你说都不用有锁了
    另外event loop就不用锁了吗?你确定吗?
    ryanking8215
        18
    ryanking8215  
    OP
       2014-03-12 10:20:31 +08:00
    @clino 单线程单进程的event loop不需要锁,我确定。你说几种语言的coroutine的,我不是了解很多语言,单从lua讲,是单线程内执行的协程,不需要锁。 至于goroutine,是多线程支撑的CSP模型,需要锁的,它也提供的sync.Mutex,sync.Atomic,当然它提供更方便的chan是另一说了
    clino
        19
    clino  
       2014-03-12 10:46:14 +08:00
    @ryanking8215 gevent是单线程的,它一样提供锁的工具( http://xlambda.com/gevent-tutorial/#_11 ),可以用来"限制并发访问或运行",当然也可以不用
    不过 event loop 确实就没办法用了,所以在这点上也能看出这种编程接口没coroutine灵活
    至于goroutine,你要想做成单线程一样也可以,这是使用者的选择,不一定非要用多线程的方式
    ryanking8215
        20
    ryanking8215  
    OP
       2014-03-12 11:39:13 +08:00
    @clino 我看了一下gevent,我同意你的说法。我的理解是从资源保护上讲,是不需要锁的,因为gevent的cpu是用户显示释放的,不是OS调度的,没有临界区的问题,但是你要同步gevent,控制gevent的执行顺序,就需要信号量和锁了。

    但是你说的关于goroutine的,我不太认同,goroutine是go runtime的调度器调度的,什么时候切换goroutine是自动的,不是用户控制的,如果没有互斥和同步原语,我觉得是有临界区问题的。我不清楚如何起n个gorouine是保证在一个线程上的。
    clino
        21
    clino  
       2014-03-12 12:48:21 +08:00
    @ryanking8215 你保证是在一个线程里使用 goroutine 不就可以保证这个线程里的goroutine不会并行执行了嘛
    用不用多线程或者多进程难道你不能决定吗?
    ryanking8215
        22
    ryanking8215  
    OP
       2014-03-12 13:17:41 +08:00
    @clino goroutine和lua的coroutine还有gevent等这种协程是不同的概念。
    协程生成在哪个线程上,就在哪个线程进行上下文切换,

    但在golang里没有线程的概念,goroutine的这种设计屏蔽了操作系统的线程,目前的并发是使用线程来实现的,m个goroutine跑在n个线程上(m>=n),当你起goroutine时,golang的调度器负责将goroutie分配给已有线程或者新建线程。

    你可以安装golang跑个例子看看
    clino
        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的这篇文章"
    ryanking8215
        24
    ryanking8215  
    OP
       2014-03-12 14:02:01 +08:00
    @clino http://golang.org/pkg/runtime/#GOMAXPROCS, 是设置多少个cpu参与并行,而不是线程数。

    这篇东西完全在误导!

    我刚才试了了一下:
    func main() {
    <- time.After(5*time.Minute)
    }
    简单的定时器,golang帮我开了5个线程,包括主线程,通过ls /proc/<pid>/task/查看
    clino
        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 的异步包装(当然功能上会有一些限制)"
    ryanking8215
        26
    ryanking8215  
    OP
       2014-03-12 15:18:36 +08:00
    @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):并发是逻辑上的“并发”,并行是物理上的“并发”。
    clino
        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")
    }
    ryanking8215
        28
    ryanking8215  
    OP
       2014-03-12 16:32:34 +08:00
    这个是golang的调度器实现的,具体的我也不懂了,没研究过。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1750 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 00:35 · PVG 08:35 · LAX 17:35 · JFK 20:35
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.