V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
ray1888
V2EX  ›  程序员

go 协程问题

  •  
  •   ray1888 ·
    ray1888 · 2017-10-31 22:51:24 +08:00 · 4173 次点击
    这是一个创建于 2580 天前的主题,其中的信息可能已经有所发展或是发生改变。

    刚刚接触 go 语言,想请问一个问题,go routine 是如何在后台可以完成耗时的任务而不阻塞当前的任务的呢?

    像 python 的 Tornado 可以使用 Thread.Exector 来进行调度,等这个协程跑完之后可以切换到新建的线程池中来进行耗时的操作的处理,也可以使用 asyncio 里面,先把协程任务跑完,然后在最后的事件循环中添加任务来让耗时任务运行。

    求 go 语言的高手们解答一下。

    13 条回复    2017-11-01 14:03:38 +08:00
    ryd994
        1
    ryd994  
       2017-10-31 23:38:34 +08:00 via Android
    举个例子,对于 socket,用 select
    你自己写 select 也是一个效果,但是 go 把这个机制做到运行环境里,再用语法糖使得这个流程就像线程一样易于理解和开发
    你可以看看这个视频
    changwei
        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,不存在线程创建过多之后带来线程切换的性能损失。把并发程序的开发简化了很多。
    halfer53
        3
    halfer53  
       2017-11-01 03:36:37 +08:00 via Android   ❤️ 1
    go 自身有一个调度器,当其中一个协程调用 blocking syscall,比如 read,go 的调度器回自动检测到,并把同一 socket 下的其他协程切换到其他 socket 去。等 syscall 完成以后,再恢复原状
    halfer53
        4
    halfer53  
       2017-11-01 03:37:55 +08:00 via Android
    我说的 socket 指的是多核 cpu 下的每一个核
    janxin
        5
    janxin  
       2017-11-01 07:26:12 +08:00 via iPhone
    lz 是否只用过 python 或者只了解过 python 的并发编程?建议从几种常见的并发编程模型入手更容易理解
    araraloren
        6
    araraloren  
       2017-11-01 09:00:19 +08:00
    建议你看看这一篇文章,那得根据耗时的任务类型区别对待。。
    https://studygolang.com/articles/2357
    ray1888
        7
    ray1888  
    OP
       2017-11-01 09:22:57 +08:00
    @janxin 因为 python 会用得比较多,以前大学学的 java 和 c++都太久没用,所以现在思路主要是以 python 为主
    ray1888
        8
    ray1888  
    OP
       2017-11-01 09:23:24 +08:00
    @ryd994 能直接把视频链接放上来吗?你之前烤的那个视频挂掉了
    ZSeptember
        9
    ZSeptember  
       2017-11-01 09:47:17 +08:00
    你看操作系统怎么同时完成多个任务的,当然在微观上同时执行的只有几个任务。
    Go 就是这样实现的,Go 的 runtime 实现了一个类似于操作系统的调度器,然后编译器在在函数调用或者什么其他的地方插入一下检查函数,如果 go routine 执行时间过长,就抢占了,执行其他任务
    IO 最终都会是系统调用,在系统调用的入口处理一下,就可以使用系统提供的 epoll 之类的了
    alexsunxl
        10
    alexsunxl  
       2017-11-01 09:50:25 +08:00
    @ray1888 视频没挂,youtube 的
    ray1888
        11
    ray1888  
    OP
       2017-11-01 09:51:06 +08:00
    @alexsunxl 挂上$$之后就看到了,谢谢
    zts1993
        12
    zts1993  
       2017-11-01 09:52:27 +08:00
    主要两种
    io 类自动转为 non-blocking,epoll trigger 之后恢复 context,继续执行之前的 goroutine
    syscall 类的,超时之后会吧队列中其他待执行的移到另一个新 thread 中运行。

    可以了解一下 golang M P G
    HarrisonZ
        13
    HarrisonZ  
       2017-11-01 14:03:38 +08:00
    golang 官网的文档先看看吧
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2815 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 79ms · UTC 09:33 · PVG 17:33 · LAX 01:33 · JFK 04:33
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.