协程真正的作用是什么 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
PiersSoCool
V2EX    Go 编程语言

协程真正的作用是什么

  •  
  •   PiersSoCool 2020-09-09 14:46:03 +08:00 6666 次点击
    这是一个创建于 1860 天前的主题,其中的信息可能已经有所发展或是发生改变。

    这里我想出个判断题,看看大家想的是不是一致的

    相对于线程来说,假设有很多请求,假设是 Golang 语言

    1. 协程处理 IO 很快
    2. 协程处理高并发很快
    3. 协程上下文开销很少
    4. 协程占用资源很少

    这里面是都是正确的吗?

    28 条回复    2020-09-10 14:02:50 +08:00
    hdbzsgm
        1
    hdbzsgm  
       2020-09-09 14:49:55 +08:00   2
    不加场景的话 严格说都不对 协程可以提一句 降低上下文切换频次
    misaka19000
        2
    misaka19000  
       2020-09-09 14:50:00 +08:00   2
    以前是为了充分利用 CPU 资源(在现代操作系统出现之前);
    现在是为了简化异步操作,提升程序员编写代码的简洁性;
    OwO233
        3
    OwO233  
       2020-09-09 14:50:34 +08:00
    https://www.zhihu.com/question/20511233
    谷歌搜到了知乎的湖大,感觉很牛,尼康康。OwO
    caskeep
        5
    caskeep  
       2020-09-09 14:52:40 +08:00 via iPhone
    @misaka19000 #2 +1 切换到 go 就是为了异步处理省事好写...
    ysc3839
        6
    ysc3839  
       2020-09-09 15:05:05 +08:00
    感觉网上讨论“协程”更多是指有调度器的,单线程执行的协程。我自己没有接触过,并不太了解。
    我自己最早接触协程是 Python 和 Javascript 的 async fuction 和 generator,这里的协程是一种可以中途返回,后面再恢复执行的函数,现在 C++ 20 的协程也是属于这一类。
    如果讨论是后面这种协程的话,那处理 IO 快不快、上下文开销大不大,完全取决于怎么实现的,用户可以用线程池+同步 IO 。
    wysnylc
        7
    wysnylc  
       2020-09-09 15:23:54 +08:00
    把多线程能解决的问题搞复杂,把多线程不能解决的问题解决掉
    FutherAll
        8
    FutherAll  
       2020-09-09 15:32:17 +08:00
    goroutine 就是减少频繁的线程上下文切换带来的 CPU 消耗吧,以及 goroutine 占用的内存空间更小。
    G-P-M 模型,真正需要切换线程是在 M 的切换,G 的切换是 go 在用户态实现的调度器来做的,更像是一种用户态线程。
    lambdaq
        9
    lambdaq  
       2020-09-09 15:40:06 +08:00
    真正的作用,那就是处理能力分时啊。。
    noe132
        10
    noe132  
       2020-09-09 15:54:57 +08:00 via Android   1
    协程是单线程异步,你不需要处理锁的问题
    keepeye
        11
    keepeye  
       2020-09-09 16:28:04 +08:00
    goroutine 是多线程协程,能并行的,跟别的语言的单线程协程还是有很大不同的
    PiersSoCool
        12
    PiersSoCool  
    OP
       2020-09-09 16:34:40 +08:00
    感谢大家。

    感觉协程在 JS 来说可能语法上更加方便。

    我可能看了一些奇怪的文章,说协程能提升 IO 速度搞得我十分困惑。我是觉得 IO 问题是多路复用解决的。
    PiersSoCool
        13
    PiersSoCool  
    OP
       2020-09-09 16:35:34 +08:00
    我感觉 go 的协程可以解决一些问题,创建 1000 个线程任务的代价和创建 1000 个协程任务(可能只有几个线程)的代价是不一样的,上下文大部分情况应该都是相同的,上下文切换次数也是不一样的。
        14
    zhangfeiwudi  
       2020-09-09 16:38:03 +08:00
    协程上下文开销很少
    协程占用资源很少
    这两对的
    在这两个的前提下 ,才有“协程处理高并发很快”

    因为携程切换都是在用户态进行,所以速度很快,而且每次切换保留现场的资源很少
    PDX
        15
    PDX  
       2020-09-09 16:42:39 +08:00 via iPhone
    我觉得解决回调地狱是最大的作用
    lbp0200
        16
    lbp0200  
       2020-09-09 16:48:37 +08:00
    协程处理 IO 很快

    一百万 IO 任务需要处理
    用线程解决,同时只能启动 1000 个
    用协程解决,同时只能启动 100000 个

    你猜,最后哪种解决方案先完成,先完成的解决方案,算不算快?
    PiersSoCool
        17
    PiersSoCool  
    OP
       2020-09-09 17:17:54 +08:00
    @lbp0200 我觉得在这两个处理 IO 速度是一样的,Golang 里协程也是通过线程实现的,最后都要走到系统调用上,假设采取的都是同样的 IO 技术,无论到没到达系统 IO 瓶颈,速度都是一样的,甚至说,线程还能比协程快一些。以我的了解,像这种阻塞的系统调用,并发启动 100000 个协程 = 启动 启动 100000 个线程,会爆炸的。不知道是不是对的。
    linw1995
        18
    linw1995  
       2020-09-09 19:32:23 +08:00
    1. 用协程也是有用到锁的时候
    2. 协程减少了上下文切换的时间
    3. 用起来更方便,可以控制每个协程的状态(有的实现例外)
    optional
        19
    optional  
       2020-09-09 19:40:12 +08:00 via iPhone
    减少线程的上下文切换。
    akagishigeru
        20
    akagishigeru  
       2020-09-09 21:26:06 +08:00 via iPhone
    3 是重点 用户态的切换开销小
    Aoang
        21
    Aoang  
       2020-09-09 22:11:38 +08:00 via Android
    @PiersSoCool 10w 协程不可能等同于 10w 线程。
    IO 堵塞的时候,线程切换的开销多大?这还没提机器,创建线程的资源大小能和协程相比么…

    如果不考虑多路复用,协程会吊打线程。实际应用中,因为多路复用会导致两者差异并不是非常大。
    但是如果线程与线程之间需要传输资源…差距又会被拉很大。
    而且线程是比协程复杂的多的…玩的不好……就不用说了
    cmdOptionKana
        22
    cmdOptionKana  
       2020-09-09 22:19:56 +08:00
    @PiersSoCool 不对,Golang 只是在有需要的时候自动开线程以充分利用 CPU,协程与线程不是一比一,而是多比一。
    Acoolda
        23
    Acoolda  
       2020-09-09 23:14:33 +08:00 via Android
    就是合集利用 io 等待时间来执行其他任务,让 cpu 一直处于忙的状态
    hakono
        24
    hakono  
       2020-09-09 23:31:00 +08:00   1
    说个我的看法
    我觉得只需要记住一点就行了: 协程不能改善计算密集型任务的执行效率,但却能极大改善大量需要 白 白 干 等 的任务(典型就是 IO 密集)的执行效率

    其实在这里是有一个界限的,线程数量少的时候其实用多线程还是协程差别没那么大。但是当线程非常多,切换开销过大时,协程的优点才会显现,1,2,3,4 才会大致成立(比如大量 IO 请求)

    其实对人类来说,协程才是我们最熟悉、用得最多的处理事情的逻辑。不如说大部分时候我们都是在用协程的思维在处理事情的。即便是对编程一无所知的大妈,平时做饭时都在用协程思维:在烤面包的空档去切菜做其他事情,而不是烤面包的时候就在那干等面包烤完。这就是典型的协程思维。 烤面包需要好几分钟,这好几分钟是白白干等的,相当于做 IO 请求( IO 请求和 cpu 处理速度相比是非常慢的)。这 IO 请求的空档 cpu 完全能去做其他事情而不是在那干等。

    所以理解到这层之后,就会发现我们生活处处都是在用协程做事。然后什么情况协程比线程更好也能比较好判断了
    hakono
        25
    hakono  
       2020-09-09 23:31:55 +08:00
    对了,追加个 go 协程相关的,这个上面已经有人说了:

    讨论协程要区分一般意义上说的协程 和 go 语言的协程( goroutines )
    一般意义上单线程里跑的协程是无法利用多个核心的资源的(毕竟开再多协程都是在一个线程里跑,没法利用多个核心)。解决办法就是开几个线程,把协程分配到这些线程里执行,这样就能完全利用 cpu 了

    go 语言的协程就是后者,在协程的基础上自带调度器,会根据需求创建多个线程然后把协程分配到不同线程里运行,从而利用多个核心。写代码的人根本不用去纠结该开几个线程,每个协程该怎么调度
    reus
        26
    reus  
       2020-09-10 04:08:53 +08:00
    goroutine 又不是协程。
    12101111
        27
    12101111  
       2020-09-10 09:41:20 +08:00
    1.协程处理 IO 很快
    协程不会让 IO 操作变快,但是可以在等待 IO 操作时执行其他协程,也就是提高了吞吐量
    2.协程处理高并发很快
    同 1, 吞吐量大了才能处理高并发
    3.协程上下文开销很少
    相较于 fork join 模式,线程池+有栈协程的开销更小,但是 Rust 的无栈协程才是无开销的模式
    创建线程需要操作系统分配完整的栈+TCB, 而创建有栈协程只需要分配较小的栈+运行时自己调度,无栈协程在编译时直接变成状态机,运行时建立这个状态机就一直执行下去了,不需要分配栈.
    4.协程占用资源很少
    有栈协程会分配一块内存作为栈,比线程省资源
    chaleaoch
        28
    chaleaoch  
       2020-09-10 14:02:50 +08:00
    234 吧.
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5503 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 28ms UTC 08:30 PVG 16:30 LAX 01:30 JFK 04:30
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86