Hello World
Spiga

为什么我认为goroutine和channel是把别的平台上类库的功能内置在语言里

2013-04-09 13:52 by 老赵, 12576 visits

这几天看了《Go语言编程》这本书,感觉一般,具体可见这篇书评。书评里面我提到“Go语言的goroutine和channel其实是把别的语言/平台上类库的功能内置到语言里”,这句话当然单单这么说出来是没什么价值的,于是我也就趁热把它说得再详细一些。我的看法简而言之是:由goroutine和channel所带来的主要编程范式、设计思路等等,其实基本都可以在其他一些平台中配合特定的类库来实现。

我们知道,操作系统的最小调度单元是“线程”,要执行任何一段代码,都必须落实到“线程”上。可惜线程太重,资源占用太高,频繁创建销毁会带来比较严重的性能问题,于是又诞生出线程池之类的常见使用模式。也是类似的原因,“阻塞”一个线程往往不是一个好主意,因为线程虽然暂停了,但是它所占用的资源还在。线程的暂停和继续对于调度器都会带来压力,而且线程越多,调度时的开销便越大,这其中的平衡很难把握。

正因为如此,也有人提出并实现了fibercoroutine这样的东西,所谓fiber便是一个比线程更小的代码执行单位,假如说“线程”是用来计算的“物理”资源,那么fiber就可以认为是计算的“逻辑”资源了。从理念上说,goroutine和WebWorker都是类似fiber或coroutine这样的概念(所以叫做goroutine):它们都是执行逻辑的计算单元,我们可以创建大量此类单元而不用担心占用过多资源,自有调度器来使用一个或多个线程来执行它们的逻辑。

Go语言使用go关键字来将任意一条语句放到一个coroutine上去运行。假如只是简单地执行一段逻辑,那么这和丢一段代码去线程池里执行可以说没有任何区别。但关键就在于,由于一个coroutine几乎就是个普通的对象,因此我们往往可以放心地阻塞它的逻辑,一旦阻塞调度器可以让当前线程立即去执行其他fiber上的代码。这里的阻塞往往就是通过Go语言中的channel带来的,一般来说会发生在“读”和“写”的时候:

func DoSomething(ch chan int) {
    ch <- 1
    var i = <-ch
}

上面代码中的ch就是一个用来保存int类型数据的channel。第一行代码是向其写入数据,可能在channel写满的时候阻塞。第二行则是从中获取数据,在channel为空的时候阻塞。可以看出,所谓channel其实就是一个再简单不过的容器而已。假如要类比.NET类库,则可以认为它是一个实现了ITargetBlockISourceBlock的对象(例如一个BufferBlock):

static async void DoSomething<T>(T block) where T : ISourceBlock<int>, ITargetBlock<int> {
    await block.SendAsync(1);
    var i = await block.ReceiveAsync();
}

类似Go语言中的超时等特性自然也一应俱全。当然,这里还并不能完全说是“类库”,毕竟还用到了C# 5里的async/await特性。我相信假如您对async/await有所了解的话,肯定也会听到一些它跟coroutine相关或类比的声音。它们在概念和效果上的确十分相似,当然背后的实现是有很大不同的。假如你一定要用coroutine,那还是免不了由语言或运行时提供支持。不过基于goroutine和channel的编程模式几乎完全可以由类库来实现。

在Go语言中,基于goroutine和channel的编程模式往往是这样的:

func (ch chan int) {
    for { // 死循环
        var msg = <-ch

        Process(msg)
    }
}

这样的“代码编写模式”是基于阻塞的,这需要coroutine支持。不过假如我们把需求分析到最基础的部分,它其实仅仅是:

  1. 可以创建大量队列,每个队列可以保存大量任务。
  2. 单个队列中的任务严格串行。
  3. 尽可能高效地(自然可以并行)处理系统中所有队列里的任务。

这就完全是类库能实现的功能了,各个平台上的此类成熟类库并不少见:

  1. iOS上的GCD,或者说libdispatch。
  2. Java平台上与GCD理念相同的HawtDispatch类库。
  3. 与Scala语言关系更为密切的Akka类库。
  4. .NET中的TPL Dataflow(之前提到的BufferBlock的出处)。

这些类库与Go语言中基于goroutine和channel的开发方式有着相似的基础,也完全有能力使用同样的方式来架构系统。基于这些类库,我们只需要提交大量的任务,至于这些任务什么时候被执行则是内部实现所关心的问题,类库自身将会把这些任务调度到物理线程上执行,用一种最高效,代价最低的方式。当然,我们也可以对这些队列进行一些配置,这甚至比Go或Erlang中直接由语言运行时来提供的调度支持有更细致的控制粒度。

我在工作中用过HawtDispatch和TPL Dataflow,也深刻体会到它们的价值。尤其是后者,我用TPL Dataflow实现的业务更为复杂,简直可以说大大改善了我的工作品质,拿它来模仿之前的编程模式则可以是这样的:

var block = new ActionBlock<int>(Process);

往这个block对象里塞入的任何对象都会使用Process方法进行处理。当然TPL Dataflow的功能不止如此,它有着大量的高级功能,例如TransformBlock可以在保证顺序的情况下进行一对多的数据转换,十分好用。具体内容可以参考这篇说明

当然,像Go与Erlang这种对coroutine和并发直接提供支持的语言还可以有其他一些做法,例如Go可以做到先从channel A中获取数据,然后在一个逻辑分支中再从channel B中获取数据。这对于只提供任务队列的类库来说做起来就麻烦一些了(对于C#和Scala这类语言来说依然不成问题),不过在我的经验里这个限制似乎并不会成为严重的阻碍,我们依然可以实现相同消息架构。

说起Erlang,其实在我看来它比Go的channel要好用不少。原因在于Erlang是动态类型语言,它的receive操作可以用来匹配当前队列(在Erlang里叫做mailbox)中不同模式的元组,筛选出符合特定模式的消息。与此相反,Go是静态类型语言,它总是从一个channel中依次获取类型相同的元素,这就完全类似于Java或C#中的泛型集合了。当然,这也不会是个影响系统设计的大问题。

说实话,我觉得这篇文章描述过多,但缺乏案例。其实我本来想通过改写《Go语言编程》中的范例来说明问题,但后来发现书中关于channel和goroutine的例子实在太简单了,没法体现出一个这个特性所带来“架构设计”。所以,示例什么的找机会再说吧。

Creative Commons License

本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名赵劼(包含链接),具体操作方式可参考此处。如您有任何疑问或者授权方面的协商,请给我留言

Add your comment

65 条回复

  1. astaxie
    114.80.133.*
    链接

    astaxie 2013-04-09 14:39:31

    其实任何语言都可以实现类似goroutine和channel的方式,因为这仅仅是CSP的一种理念,所以你会觉得其实OC/Java/C#等都实现了类似的类库,但是go里面的这个操作你会觉得编写并发相当的简单,只需要go 函数就可以并发了,然后不同的通道通过channel来交互数据,至于你说的channel只能获取相同的元素,这个我觉得可以使用interface来实现动态的元素传递。

    这里有一篇文章介绍的Go的并发之美我觉得很好的描述了Go的goroutine带来架构设计:http://www.yankay.com/go-clear-concurreny/

  2. 老赵
    admin
    链接

    老赵 2013-04-09 15:21:37

    @astaxie

    你也可以在其他语言里为自己准备一个Go函数来并发,此外用interface来实现动态元素传递也是最普通的其他语言都能做到的workaround么……

    其实我说的就是,goroutine并没有带来的什么新的些架构设计。你给的那篇文章其实并没有说Go,更像是用Go来举例说明这种基于coroutine的架构设计,各种语言都能轻松实现。

  3. runner.mei
    58.246.2.*
    链接

    runner.mei 2013-04-09 16:10:15

    我非常赞同你的观点, 它就是把别的平台上类库的功能内置在语言里, 这个好处就是简单, 只给你一种方法解决问题,省得你难以选择.

    另外我对你的对channel的理解有一点不一样, channel在go中的内部实现确实就是一个queue, 但在go语言中channel它不是用来传递任务或动作的, 而主要是用于两个 goroutine 之间传递消息的.这个消息是用于两个 goroutine 为完成一个共同任务的协调信息, 而不是任务本身.

    当然, 你也可以将它作为一个任务队列使用.

  4. 老赵
    admin
    链接

    老赵 2013-04-09 16:21:50

    @runner.mei

    用来放消息还是放任务是一个概念,或者说就是个“保存对象”的作用,对象带行为那就是任务,不带行为那么就是纯消息,区别在于行为定义的位置。我举的那些类库完全也可以按照发送消息(纯数据),完全就看你怎么用了。用文章里的话就是说,不影响架构设计方式。

  5. runner.mei
    58.246.2.*
    链接

    runner.mei 2013-04-09 17:19:24

    用来放消息还是放任务是一个概念,或者说就是个“保存对象”的作用

    这个就是你我对channel理解的区别, 我认为 channel 是交流的手段. 从channel默认将队列长度设置为0可以看出这一点。

  6. 老赵
    admin
    链接

    老赵 2013-04-09 17:36:16

    @runner.mei

    对于类库来说不涉及具体的理解方式,换句话说,只要可以实现你理解的东西就行,此外还可以实现别的,只不过我们暂时不谈别的。

    类库么就是工具,就是提供这么一些功能,具体怎么用,表达什么概念,怎么参与设计,是使用者的选择。

  7. MaskRay
    59.66.131.*
    链接

    MaskRay 2013-04-09 18:59:43

    對,message-passing concurrency的兩種實現方式:channel(Go)、actor(Erlang),兩者各有千秋。

  8. days
    115.196.143.*
    链接

    days 2013-04-09 19:20:07

    最早入行的时候,总觉得无的不能,面临所有需求都会很简单的,怎么怎么做就可以了。到后来慢慢知道,这个世界不是yes和no的世界,能做和做的好是两个概念。有时候做的不好=不能做。 如果仅仅是以能做和不能做来判定,那么纸带式的二进制编程会是主导性的开发方式,不会有什么高级语言。

  9. 老赵
    admin
    链接

    老赵 2013-04-09 19:46:39

    @days

    又来这种套话,我只是说做或不能做了么?你觉得我不懂这道理还会批评Java语言么?文章都不看就来装逼好蛋疼。

  10. afutureboss
    114.249.231.*
    链接

    afutureboss 2013-04-09 20:11:31

    菜鸟,看不懂,你能不能写点水文,教教我们这些菜怎么发展

  11. tony
    122.224.121.*
    链接

    tony 2013-04-09 22:55:13

    用库可以搞。但是语言层支持,有一个好处是:调度器可以不断的优化,增加阻塞切出点。比如:channel本身,本地磁盘文件io,系统调用等等。要同步非阻塞,需要一揽子的基础设施。我觉得java做不到这个。erlang做到了,而且比目前的go做的更好。

  12. 老赵
    admin
    链接

    老赵 2013-04-09 23:19:38

    @tony

    库也可以不断优化的,你说的就相当于例如在C#里的SysCallAsync()调用从伪异步变成真异步IO,而调度策略优化更加是类库本身要实现的东西了,理论上说类库可以提供的控制会更细,所以之前也有人(好像就是邓草原)提到Scala的调度策略就没有Erlang里出现的什么问题。

    你说的同步非阻塞,这当然不是Java靠类库能做到的,我文章里说的很清楚,可以再仔细读读。

  13. douzifly
    218.17.158.*
    链接

    douzifly 2013-04-10 09:41:00

    分析的很到位~学习了。

  14. DT
    210.13.75.*
    链接

    DT 2013-04-10 13:23:09

    文章让我想到了在ObjC中一般会是用@“”字符串,而不太会用C字符串和它的字符串库函数,虽然功能上基本是等价的, 对于Golang内化并发库的好处,我的理解它更多是一种语法糖,对比示例中C#代码和Golang代码,哪个更优雅就很明显了 (虽然C#也内化了await等关键字),而一个好的语法糖就为功能的大规模应用做好准备。

  15. 老赵
    admin
    链接

    老赵 2013-04-10 18:00:10

    @DT

    还真不觉得哪个更优雅,优雅的意思只是省字符么?那么Go还真挺优雅的,既有var又有:=

  16. reus
    113.107.164.*
    链接

    reus 2013-04-10 21:21:21

    select结构怎样实现?

  17. 老赵
    admin
    链接

    老赵 2013-04-10 22:19:10

    @reus

    似乎没法简单实现,一直没搞懂它的使用场景是?

  18. reus
    113.107.164.*
    链接

    reus 2013-04-11 13:37:56

    因为golang是强类型语言,所以一个进程需要同时接收多种类型的消息时,就要使用多个channel。select可以同时进行多个channel的读和写。和posix的select类似。但也像进程一样,轻量很多。golang确实没有什么新鲜概念,用os提供的线程管道epoll/iocp之类也能实现,但把这些机制做得廉价,可以大量使用,就是其他环境提供不了的了。

  19. 老赵
    admin
    链接

    老赵 2013-04-11 14:09:37

    @reus

    假如是解决这点,那就是相当于Merge了多根管道——这跟Erlang里同一个Mailbox放各种不同元素的场景还是不同的……

  20. 科技球
    216.239.45.*
    链接

    科技球 2013-04-12 03:03:37

    我不觉得go channel的模式“往往”是for循环然后process。这只不过是一个简单的例子罢了。

    其实你文中也提到了,我觉得一个更常见的用例是:

    从channel中取msg
    从Data Source A中取data (用channel实现的异步)
    if (条件1) {
        从Data Source B中取data (用channel实现的异步)
        Combine data from A and B
    } else {
        从Data Source C中取data (用channel实现的异步)
        Combine data from A and C
    }
    send result back to some channel
    

    固然,用所谓的Workflow和Dependency Graph也可以表达出上面的这段逻辑。只是说,这样做好不好.如果一种逻辑接近programming的control flow,是不是一个语言让它本身就可以表达这种control flow而不是用数据去表达更make sense一些。我记得类似的argument你在支持Jscex以及F# Computational Expression也用过,可是为了说明go没有那么好你却走到了这个argument的相反面。

  21. 老赵
    admin
    链接

    老赵 2013-04-12 09:50:27

    @科技球

    简单说一句,设计架构和逻辑表达是两码事。大层面上我甚至不觉得Java使用这种架构方法有什么问题,小层面上都不谈coroutine了,连Lambda不支持我都觉得不爽了。当然我其实不想说这个。

    我觉得某些Go粉(又给人贴标签了么)真心让人无语,莫名其妙就把我推到了Go的反面,我这篇文章只是在说一种“情况”,你甚至可以认为是“其他平台如何使用Go语言式设计架构”,为什么要认为我在说Go不好?我的书评里也说“用语言来强调编程方式是一种文化,Erlang就是前例”,而且有些地方既然你都知道我文中也提到了,你还认为我在说Go坏话?非要明文把Go夸到天上有地下无你们才满意么?

    有必要那么敏感脆弱么。

  22. 科技球
    76.21.115.*
    链接

    科技球 2013-04-12 11:16:56

    我不是go粉,我其实没有机会写过一行go的程序,我只是有兴趣思考各种编程语言带来编程思想上的改变。我也没有说你走到了go的相反面,我说的是你走到了语言层面支持比类库支持更好这个argument的相反面。当然你可能不是这样认为的。你在文章里说,“go语言的goroutine和channel其实是把别的语言/平台上类库的功能内置到语言里”,我可能错误理解你的意思,但这句话的语感更像是"XXX其实就是YYY,没什么大不了的"。但是你在Jscex和F# Computational Expression的观点是:“XXX虽然可以通过YYY做到,但是XXX带来的是思想上的改变和飞跃”,所以我才这样子说的,并没有想冒犯你的意思。

    就我个人观点而言,go的channel机制虽然可以通过类库实现,但仍然是编程思想上的一种飞跃,理由同Jscex和F# Computational Expression。当然你可以说是go借鉴了这些东西,只是从时间上说,这些东西至少是同时被发明出来的。另外,我个人感觉go的channel稍稍比F#和C#的async和await更make sense一些,理由我不详述了,如果有时间的话我会写写的。

  23. 老赵
    admin
    链接

    老赵 2013-04-12 11:29:58

    @科技球

    “没有什么大不了的”就是我说的敏感脆弱了,我根本没这么说,唉,更何况我都说了这也是一种语言文化,何必呢。

    此外,我也没有说过“语言支持比类库更好”这种话,我说Jscex或F# Computation Expression更好,都是建立在它们跟传统类库相比做得更好的前提上的。我对他们的支持当然会谈到思想,但更多是思想A比思想B更方便(也就是说并非“虽然XXX也可以通过YYY做到”,或者说能做到但可以做更好),不是为了思想而思想的……

  24. tokimeki
    61.57.134.*
    链接

    tokimeki 2013-04-13 14:13:05

    我想到一個比喻來看線程跟 goroutine / channel:前者像在高速公路開車,後者像在跑接力賽。

    我同意你說的在其他語言上可以用類庫來表現 goroutine / channel,不過 Go 把這個能力放到語言層級應該也沒關係吧?

  25. 爱围观
    219.128.48.*
    链接

    爱围观 2013-04-30 08:51:55

    c#挺强大的,啥功能都有。够人研究一辈子。

    go貌似是建立在单纯的协作式线程上的,语言本身限制了抢占式的线程,目的好像是为了并发啥的。

    线程池怎么模拟这个 runtime.Gosched() yields/让步?

  26. damon
    218.109.158.*
    链接

    damon 2013-05-08 23:18:19

    语言层面支持的和库支持的,还是有一些差别的.比方说gc功能,c++也可以通过类库的方式支持(简单的引用技术),但是C#直接的语言层面支持,就可以减少考虑很多.另外,语言层面支持的map和库支持的map,也是存在一些差别的.java或者c#的包技术,c++也可以通过创建文件夹的方式来做,但是与内建必须的有差别的是,c++的大量工程可能分包并没有java和c#那么通用,沟通成本也更高一些.

    另一个就是库可以被另一个库替换,这个时候就会存在一些沟通上的成本,也就是两个人都需要同时知道这个库才能更好沟通.语言层面的支持,就是说如果你熟悉这个语言,那么就可以直接进行沟通.相比较库,成本会轻量级一些.

    所以我是比较支持在语言层面做一些常见的事情的集成.不过go的写法和go的用法,我个人感觉也不是特别的好

  27. 我傻逼我自豪
    120.6.154.*
    链接

    我傻逼我自豪 2013-05-12 06:37:33

    如果是动态语言的coroutine可能还真的需要在语言中集成支持,因为调度单元毕竟是种抽象基础设施(不同的VM上有不同实现,共享哪些上下文资源由语言决定),语言不提供库就用不了(对于基础库/内置库/标准库由C或其他静态编译语言实现的情况就当我没说过);但是静态语言么……Windows上有fiber,泛Unix上有setjmp&longjmp/ucontext,已经说明了coroutine可以独立于语言实现。

    PS:WebWorker更像是多线程模型而非coroutine。若干个WebWorkers可以并发执行。

  28. 老赵
    admin
    链接

    老赵 2013-05-12 15:48:25

    @我傻逼我自豪

    coroutine也没说不能并发执行了。把WebWorker跟coroutine类比也是因为它们都可以开大量的对象,跟线程不直接对应。

  29. 我傻逼我自豪
    120.6.154.*
    链接

    我傻逼我自豪 2013-05-13 02:26:21

    @老赵

    “现代的”浏览器一般都会把WebWorker绑定到线程,至少渲染线程和WebWorker线程必须分开,否则一做大计算,渲染线程就卡住了,然后页面假死,半天点不了。当然可以用coroutine的形式实现WebWorker,但是可用性很差。从这一点上来说,WebWorker和coroutine确实不等价。

    Coroutine本来就是用户级线程的一个等价模型,用系统级线程来实现,其一是太重型,切换开销大;其二是本来单线程无锁访问各种数据的优势就不存在了(当然这个优势也是用可伸缩性换来的)。一般来说,单个系统级线程上的多个coroutine之间一定不存在并发,如果有并发就说明coroutine是用多个系统线程实现的,而这又是另外一个问题了。

  30. 老赵
    admin
    链接

    老赵 2013-05-13 13:13:01

    @我傻逼我自豪: 单个系统级线程上的多个coroutine之间一定不存在并发

    假如是你说的这点,那么WebWorker的确跟coroutine不等价,但我不觉得有这个说法,所以我觉得它们是一种东西。

  31. 我傻逼我自豪
    120.6.154.*
    链接

    我傻逼我自豪 2013-05-13 17:25:16

    @老赵

    其实我们之间就一个认识差异:老赵你认同coroutine可以用任何可接受的方法实现,而我认同coroutine必须用用户级线程实现(不然我认为没有意义),仅此而已。

  32. 我傻逼我自豪
    120.6.154.*
    链接

    我傻逼我自豪 2013-05-14 11:38:44

    https://en.wikipedia.org/wiki/Fiber(computerscience)

    根据以上链接的“Fibers and coroutines”一节,coroutine作为一个语言级基础设施,一般倾向于用fiber或用户级线程实现。

    https://en.wikipedia.org/wiki/Web_worker

    根据以上链接的“Overview”一节,WebWorkers被认为是:“……相对重型的。……WebWorkers允许浏览器线程和一个或多个后台Javascript线程并发执行。”

    上面的资料证实了我的观点,coroutine->用户级线程,WebWorkers->系统级线程,二者一般不等价。

  33. 老赵
    admin
    链接

    老赵 2013-05-15 11:04:09

    @我傻逼我自豪

    这里说的WebWorker的线程显然不是“系统级线程”,你可以开几十几百个WebWorker,他们是系统级线程么?这里“浏览器线程”或“JavaScript线程”本身就是指“用户级线程”,用户级线程之间也可以并发。Erlang里还都是“进程”呢,跟操作系统进程能同日而语么。

  34. 我傻逼我自豪
    120.6.154.*
    链接

    我傻逼我自豪 2013-05-15 23:35:03

    @老赵

    我发现我有时候说话论据不够充分,难以使人信服。所以我就找了一下chromium的实现:(以下源文件的根目录均为chromium官方SVN服务器中的 /trunk 路径)

    chromium/src/third_party/WebKit/Source/core/workers/WorkerThread.cpp
    

    此文件 125 行的

    bool WorkerThread::start() 函数
    

    为chromium浏览器中WebWorker线程创建的起点,调用了 createThread 函数。此函数位于

    chromium/src/third_party/WebKit/Source/wtf/Threading.cpp
    

    文件 72 行,原型如下

    ThreadIdentifier createThread(ThreadFunction entryPoint, void* data, const char* name) 
    

    调用了 createThreadInternal 函数。此函数分为 POSIX 和 Win 两个版本:

    POSIX 版本在

    chromium/src/third_party/WebKit/Source/wtf/ThreadingPthreads.cpp
    

    文件的 184 行:

    ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*)
    

    其中调用了 pthread_create 函数。根据网上的资料( http://stackoverflow.com/questions/8639150/is-pthread-library-actually-a-user-thread-solution ),我认为在Linux平台下,Chromium使用了系统级线程实现WebWorkers。

    再看Win。Windows 版本在

    chromium/src/third_party/WebKit/Source/wtf/ThreadingWin.cpp
    

    文件的 224 行:

    ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char* threadName)
    

    其中调用了 _beginthreadex MSVC C语言运行时库函数。根据网上诸多教程以及前一阵子我对crt源码的阅读,我认为在Windows平台下,Chromium使用了系统级线程实现WebWorkers。

    由于我完全不了解OSX系统,所以不太清楚 pthread 在OSX系统下使用了何种线程模型。但可以肯定的是,在Linux和Windows这两大系统上,Chromium都使用了系统级线程实现WebWorkers。也就是说,“现代”浏览器倾向于使用系统级线程实现WebWorkers。

  35. 老赵
    admin
    链接

    老赵 2013-05-16 10:47:56

    @我傻逼我自豪

    标准摘录

    Workers (as these background scripts are called herein) are relatively heavy-weight, and are not intended to be used in large numbers. For example, it would be inappropriate to launch one worker for each pixel of a four megapixel image. The examples below show some appropriate uses of workers.

    好像的确是我理解错了,那么我到底是从哪里看到说WebWorker可以创建很大量的?

    多谢纠正。

  36. 我傻逼我自豪
    120.6.154.*
    链接

    我傻逼我自豪 2013-05-16 17:45:17

    @老赵

    可能是WebWorkers标准刚出台的时候,Chrome/firefox使用了fiber/用户级线程模型,造成了误解的缘故。

    Firefox的实现没有仔细看,代码量比Chrome要大一些……

  37. 我傻逼我自豪
    120.6.154.*
    链接

    我傻逼我自豪 2013-05-16 17:56:04

    @老赵

    其实即便是系统提供的fiber/用户级线程,也不能开得太多(当然动态语言的coroutine可以,估计Ruby/Lua的coroutine开几千个没问题),因为fiber/用户级线程的栈都是独立的,开得太多会大量消耗内存资源。

    这两天我做了一个Win32绑定的coroutine实现(类似于fiber),发现4KB的栈都不够调用msvcrt的printf一次,被逼用了64KB(60KB可用,4KB保护页面),可想而知如果开得太多会怎么样。

  38. 老赵
    admin
    链接

    老赵 2013-05-16 23:13:28

    @我傻逼我自豪

    看怎么实现的,理论上完全可以做到coroutine跟系统资源无关,就是最普通不过的对象,反正只要使用效果到了就行。

  39. 我傻逼我自豪
    120.6.154.*
    链接

    我傻逼我自豪 2013-05-17 01:06:46

    @老赵

    如果是动态语言很容易写出轻量化coroutine,因为可共享资源都是VM在控制。我写的是个系统级的版本,可以替代fiber用,所以量级重一些。

  40. bombless
    113.111.120.*
    链接

    bombless 2013-05-17 14:44:48

    你这叫做双重标准。

    你以前支持C#的时候就说语法糖好,现在批其他语言了就开始说语法糖没用了……

  41. 老赵
    admin
    链接

    老赵 2013-05-17 15:14:23

    @bombless

    你这叫脑补,我从头到尾没有说这种做法是缺点,我只是做一个客观的描述,而且我文章里都说了“这也是一种文化表现”。

    所以我说Go的使用者真可怕,不明着说“Go语言好Go语言妙Go语言顶呱呱”的都当是黑。

    更何况你还真别说,C#的可都不是普通的语法糖。

  42. 老赵
    admin
    链接

    老赵 2013-05-17 15:16:03

    @我傻逼我自豪

    跟是不是VM或是不是动态语言没关系,就看编译成什么样,可以有VM,也可以直接编译成native的,不是所有的编译都得像C语言那样直白。

  43. 我傻逼我自豪
    120.6.154.*
    链接

    我傻逼我自豪 2013-05-18 01:03:37

    @老赵

    你说得对。

  44. lili
    222.69.21.*
    链接

    lili 2013-06-17 11:15:59

    @老赵 你多大了?

  45. QLeelulu
    116.21.82.*
    链接

    QLeelulu 2013-07-20 00:07:17

    你这叫脑补,我从头到尾没有说这种做法是缺点,我只是做一个客观的描述,而且我文章里都说了“这也是一种文化表现”。 所以我说Go的使用者真可怕,不明着说“Go语言好Go语言妙Go语言顶呱呱”的都当是黑。 更何况你还真别说,C#的可都不是普通的语法糖。

    哪里的go使用者是这样的啊? 话说我认识的雨痕和360的某位攻城湿都不会这样啊, 他们天天在群里黑go。

    另外对于《Go语言编程》这本书我看过后就再不会给别人推荐了, 我现在都推荐雨痕的go笔记 https://github.com/qyuhen/book

  46. hello
    118.113.227.*
    链接

    hello 2013-08-30 16:08:11

    那这么说来,“别的平台上库嵌入到语言里”的可就多了。。。能不能说很多语言都把C的链表库之类的嵌入成list、dict等?

  47. microcai
    223.93.175.*
    链接

    microcai 2013-09-03 02:07:28

    C++ 里也有这种协程调度。Boost.Asio 里的 coroutine

    Asio 的 coroutine 其实只是 closure, 注意不要和 Boost.coroutine 混淆。 asio 的 coroutine 应该最接近于 go 的 goroutine 了。

    使用的时候需要使用 BOOSTASIOCOROREENTER 和 BOOSTASIOCOROYIELD 两个宏。

    一些小介绍可以 看看 http://microcai.org/2013/03/17/stackless-coroutine.html

  48. linustd
    127.0.0.*
    链接

    linustd 2013-10-19 22:27:20

    不是“你认为”goroutine和channel是把别的平台上类库的功能内置在语言里,

    而是,“就是”goroutine和channel是把别的平台上类库的功能内置在语言里。

    开始了解go语言的时候,我发现字典等类型,竟然被Go语言内置到语言里了,很不爽,觉得这没有原则,不是最优的。

    后来还发了一个帖子声讨,结果有人回复很简单: 既然字典使用的非常频繁,为什么不能内置到语言里呢?

    go语言应该是一个兼有设计精炼,又务实求效的语言。所以把dict/goroutine/channel都内置到语言里了。

    其实.net更无耻,直接用巨大并且不断膨胀的类库实现务实的目的,这还不如go呢。

  49. xczx
    14.153.32.*
    链接

    xczx 2013-12-04 15:02:07

    我一想到事务内存,就感到一种dandan的幽桑

  50. 链接

    Join Smith 2014-04-15 17:15:56

    我正在用c#写一个多线程的程序,c#的基于内存共享数据同步真心坑爹,需要小心地避开各种死锁,然后就到你这儿,真心不敢赞同

  51. 老赵
    admin
    链接

    老赵 2014-04-24 11:36:32

    @Join Smith

    你看懂文章在说什么了吗?

  52. 我傻逼我自豪
    74.79.58.*
    链接

    我傻逼我自豪 2014-04-27 14:49:31

    老赵好久不见了,近来好吗:)

  53. qkb_75_go
    111.204.254.*
    链接

    qkb_75_go 2014-11-22 15:55:09

    其他C/C++/JAVA/PATHY语言和平台上的类库的功能,其实不过是把机器指令汇编数内置在语言或函数里的。

    老赵你到底想说什么呢?

  54. 老赵
    admin
    链接

    老赵 2014-11-23 18:03:47

    @qkb75go

    忘了,不过现在我想说,你没看懂文章。

  55. kenneth.jing
    106.187.49.*
    链接

    kenneth.jing 2015-01-29 16:38:26

    我觉得吧,楼主并没有说怎么好怎么不好,只是说go把别的平台上类库实现或可以通过类库实现的功能内置了,这个话本身没什么问题,只是个客观描述。不过,整个go都是开源的,完全可以在src/runtime下边找到chan的实现代码,又加上本身是native运行,库和内置的界限就不是那么明显了,因为所有的“内置”功能,都和库的表现是一致的,即需要才会被链接。 从使用角度而言,go本身还没有成为一个可以和.net相比的非常强大的系统,但是因为开源、跨平台、极简的设计,让它具有各种更好的潜力。因此,我本人是go的脑残粉。

  56. kenneth.jing
    106.187.49.*
    链接

    kenneth.jing 2015-01-29 17:36:19

    https://www.youtube.com/watch?v=QDDwwePbDtw google的人自己也说了,内置并发而不是通过库实现,使得语法更简洁。

  57. 链接

    liyonghelpme 2015-09-13 02:00:50

    go 从思想上确实没有什么新颖之处,优点大概就是比较知名的完全并行化的语言实现,没有同步设计的历史负担,例如c#这货一个网络库,可以有好几种编程模型。

  58. zoroseo2020
    35.241.103.*
    链接

    zoroseo2020 2021-03-17 17:57:49

    类似Go语言中的超时等特性自然也一应俱全。当然福彩双色球,这里还并不能完全说是“类库”,毕竟还用到了C# 5里的async/await特性。我相信假如您对async/await有所了解的话,肯定也会听到一些它跟coroutine相关或类比的声音澳洲幸运20。它们在概念和效果上的确十分相似,当然背后的实现是有很大不同的。假如你一定要用coroutine,那还是免不了由语言或运行时提供支持幸运飞艇。不过基于goroutine和channel的编程模式几乎完全可以由类库来实现。

  59. kericnnoe
    111.242.194.*
    链接

    kericnnoe 2022-12-21 04:06:50

    千萬不要用歐博娛樂城賺錢,因為你會變得超有錢又有美女貼著你

  60. hanababy
    35.215.175.*
    链接

    hanababy 2023-08-02 15:52:46

    "Make each day your masterpiece. 让每一天成为你的杰作。,[url=https://1687580.com/view/fc3D/index.html]100%福彩3D [/url]A man’s best friends are his ten fingers. 人最好的朋友是自己的十个手指。 (靠自己最实在) You are as warm as the sunset glow. 你与日落晚霞同样温暖。 [url=https://1687580.com/view/tcpl3/index.html]查看168排列3[/url],Crouch down, hold your knees when you are depressed. Forgive others and yourself. 忧郁的时候蹲下来抱抱自己,原谅别人,也原谅自己。 Don’t worry about the vague future, just strive for the clear present. 不为模糊不清的未来担忧,只为清清楚楚的现在努力。 [url=https://1687580.com/view/kl8/kl8_index.html]查看快乐8 [/url],Being yourself is an honor, because nobody else can be you. 做自己是一种荣耀,因为没有任何人能成为你。Crouch down, hold your knees when you are depressed. Forgive others and yourself. 忧郁的时候蹲下来抱抱自己,原谅别人,也原谅自己。,[url=https://1688363.com/]168网结果[/url]"

  61. foundation
    216.247.33.*
    链接

    foundation 2024-09-23 21:40:06

    很有趣的是,Go中的协程和通道可以被视为简化并发的内置语言特性,反映了不同平台上各种库中的模式。这表明,尽管Go提供了独特的方法,但管理任务和资源的基本概念是普遍的。这引发了一个问题:我们如何利用现有的范式来增强其他语言中的编程模型?

  62. Air Jordan
    147.185.242.*
    链接

    Air Jordan 2025-02-12 13:47:22

  63. Air Jordan
    147.185.242.*
    链接

    Air Jordan 2025-02-12 13:47:23

  64. Jordan 1
    216.126.233.*
    链接

    Jordan 1 2025-03-27 00:23:40

  65. Yeezy Slides
    104.234.236.*
    链接

    Yeezy Slides 2025-04-26 20:39:52

    Love it or hate it, the Yeezy Foam Runner has become a cultural phenomenon. From its polarizing design to its sky-high resale value, this shoe is more than just footwear—it’s a statement. Whether you’re a hypebeast, a sustainability advocate, or just someone who loves comfy kicks, here’s why the Foam Runner deserves your attention (and maybe a spot in your closet).

    1. The Design: “Ugly” Never Looked This Good When Kanye West first dropped the Foam Runner in 2020, critics called it the “weirdest Yeezy ever” 4. But fast-forward to today, and its chunky, alien-esque silhouette has become a streetwear staple. The shoe’s one-piece EVA foam construction features bold cutouts for breathability and a futuristic aesthetic that screams avant-garde 79.

    Why it works:

    Versatility: Pair it with socks for a cozy fall vibe or go barefoot for summer beach days.

    Bold Aesthetics: The organic curves and “biomorphic” design make it stand out in a sea of basic sneakers 4.

    Unisex Appeal: Available in adult, kid, and infant sizes, it’s a family flex 79.

    1. Sustainability Meets Hype Kanye promised eco-friendly innovation, and the Foam Runner delivers. Made with algae-based foam and recycled materials, each pair helps clean lakes by repurposing harmful algae 79. Even the packaging is minimalist to reduce waste.

    But let’s keep it real: While the eco-credentials are impressive, limited drops and insane resale prices (up to 10x retail!) have left fans frustrated 34. Original retail was 75 – 75–80, but scarcity pushed some colorways to $6,000+ in resale markets 34.

    1. Colorways That Keep Us Obsessed The Foam Runner’s ever-expanding palette is a masterclass in hype. Recent drops include:

    “Ochre” & “MX Cream Clay”: Earthy tones perfect for minimalist outfits (August 2 drop, $80) 210.

    “Mineral Blue”: A moody midnight hue for stealthy flexing 5.

    “Onyx”: Sleek all-black for the “dark mode” enthusiasts (released June 2022) 7.

    “MIST”: A misty brown-gray blend that sold out in seconds 9.

    Styling hacks:

    Socks + Sandals 2.0: Throw on colorful crew socks for a retro vibe.

    Techwear Essential: Match it with cargo pants and a puffer vest.

    Beach-Ready: Water-resistant material means you can rock it poolside 7.

    1. The Hype Train Isn’t Slowing Down From Walmart’s $24 knockoffs (shut down after legal battles 1) to Chinese brands like Peak copying the design 3, the Foam Runner’s influence is undeniable. But nothing beats the OG.

    Why it’s worth the hunt:

    Cultural Impact: It redefined “ugly chic” and inspired a wave of (hole-punched shoes) 6.

    Collector’s Item: Early colorways like the “Marbled” edition are grails for sneakerheads 4.

    Final Word: How to Cop Want to avoid resale scams? Stay alert for restocks! New colorways like “MXT Moon Grey” (2023) and future drops are your best shot at scoring retail 6. Set those app notifications, pray to the Yeezus, and remember: in the world of Foam Runners, patience pays.

    TL;DR: The Yeezy Foam Runner is weird, wonderful, and the shoe of the decade. Grab a pair, wear it with confidence, and join the cult.

    Ready to flex? Drop your Foam Runner stories in the comments!

    Yeezy Slides
    Yeezy Official Website
    Jordan 1
    Jordan 12
    Jordan 11
    Yeezy Slides
    NFL Shop
    NFL Store
    Yeezy Slides
    Yeezy 350
    Jordan 4
    Yeezy Supply
    Jordan 4
    Yeezy Website
    Yeezy Slides
    Jordan 12
    Jordan 11
    Jordan 1
    Air Jodan
    NFL Jerseys
    Yeezy Slides
    Yeezy Supply
    Yeezy Store
    Yeezy Slides
    Louis Vuitton Outlet
    Louis Vuitton Outlet
    Yeezy Shoes
    Yeezy Slides
    Yeezy 350
    Yeezy Slides
    Yeezy Adidas
    Yeezy Official Website
    Adidas Yeezy
    Yeezy Supply
    Yeezy Slides
    Yeezy Official
    Yeezy 350
    Yeezy Slides

    Tags:Yeezy Shoes,Yeezy Slides,Jordan 1,Air Jordan,Jordan

发表回复

登录 / 登录并记住我 ,登陆后便可删除或修改已发表的评论 (请注意保留评论内容)

昵称:(必填)

邮箱:(必填,仅用于Gavatar

主页:(可选)

评论内容(大于5个字符):

  1. Your Name yyyy-MM-dd HH:mm:ss

使用Live Messenger联系我