- 主题:觉得协程不是一个太好的编程模型
你这个理解错误。虽然你用了很久的协程。但是我觉得你太小看协程了。
协程应该是比进程、线程更高一级的抽象。和函数调用是同级别的,可以理解成异步的函数调用。
至于具体是使用线程、纤程还是进程来实现,或者根本就是混合实现那是另外的事情。在具体的调度和内存管理时,还分成 stackless, stackful 两种呢。
golang 和 java 就是典型的混合实现,纤程在线程间自动调度。
【 在 ylh1969 的大作中提到: 】
: 一般情况并不需要协程。
: 只有异步IO时,将它表达为同步,才需要。
: 简单点,在线程池网络编程中,长时间的同步IO,占用线程时间太长,影响别的任务。在等待IO期间,释放线程,由一个协程等待IO。
: ...................
--
修改:hgoldfish FROM 27.154.110.*
FROM 27.154.110.*
你这个理解也还是错误。
你那套协程之所以需要锁是因为你实现的纤程会被调度到多个线程。
但是协程也可以实现为不自由调度的。当时每个协程非常确定性的在一个线程里面运行。只能跑单核。
我们日常使用锁,实际上有两个作用:同步原语以及内存互斥屏障。
你们可以仔细想想,其实同步原语还是小事。锁更多的是后者的使用场景。如果协程只在一个线程里面被调度,那么后者是不需要的。又因为协程都是串行的。此时,只有极少的情况下需要协程锁。
【 在 ylh1969 的大作中提到: 】
: 错。
: 协程缺乏锁机制会出很多问题。
: 有人给协程写锁。
: ...................
--
FROM 27.154.110.*
内核有用协程。我记得之前 bcache 的维护者有提到他们使用了内核态的纤程。
使用协程确实可以到内核的设计进行改造。比如那个 irq 的处理过程,就是典型的协程化场景。反正,凡是异步,多多少少都可以使用协程思维进行重新改造。
【 在 overcomeunic 的大作中提到: 】
: 有了协程,更象是有了一个确定性很强的状态机
: 但这个状态机又跟业务有关,好象不管是 内核|编译器 ,都没有办法灵活地帮业务做一些定制
: 内核看着自己倒是可以用协程再提升一下性能,盲猜收益不会很大。
: ...................
--
FROM 27.154.110.*
async/await 纯粹是语法问题。都是从 c# 那边抄过来的。人家 golang 和 java 搞的协程语法就是你想的那样。在程序员看来,反正 java 的 BIO 就是同步调用。至于 java 怎么在底层转成 NIO, 那是 java 编译器的事情。
【 在 finlab 的大作中提到: 】
: 协程机制与线程混用带来更高 的复杂性。
: 异步调用到最后,还是要同步,不如一开始就同步。
: 比如,await readAsyn(); await processAsyn() 这种模式不过是为了让出空闲时间的控制权。
: ...................
--
FROM 27.154.110.*
我说的是,在语法层面是使用 async/await 还是 spawn 还是 go. 其实只是语言关键字的问题。它们的含义是差不多的。
我个人偏向使用 spawn/go 而不是传染的 async/await 丑爆了。
至于协程,具体是跨线程调度的呢,还是有栈无栈,都是另外的维度。不能和上面语法的事情混在一起说。
【 在 VincentGe 的大作中提到: 】
: async/await 的设计的角色是非常底层同步原语。
: 对于语言的模型都是同步的,async await 很好的标示一个函数如何被切分。
: #发自zSMTH@CDU.MP
: ...................
--
FROM 27.154.110.*
这完全可以从软件架构上解决。
比如对于 web 系统,系统里面有多少个核心,就启动多少个进程,大家一起抢请求就行了。本来 web 系统为了横向多机扩展,也得进程+协程的架构。
而对于一些 OLAP 类的应用,需要共享使用大量资源,问题也不大,一般仍然可以拆分出多种业务形态。
其实吧,本身拆进程就能让服务更加稳定。一个进程挂掉,还有另外的进程可以服务。
【 在 ylh1969 的大作中提到: 】
: 如果协程只能困守在一个线程,那么负载均衡就是一个问题,没有办法高效率的使用多核。
: 这个损失,可比线程协程调度时间那点差异大太多啦。
--
FROM 120.41.147.*
可以配置 go 让 goroutine 也只跑在一个线程里面。
然后启动多个 go 进程。
【 在 VincentGe 的大作中提到: 】
: 两者就不是一个并发模型,他们的差异实际上非常大。
: async/await 是协作式的,他们本身就在一个线程内。
: spawn,go的语法更多的类似异步任务的概念。
: ...................
--
修改:hgoldfish FROM 120.41.147.*
FROM 120.41.147.*
你想的事情,golang 和 java 都是这样的啊。
但是在编程的时候,访问共享资源的时候,就得注意加锁了。
golang 推荐使用 chan 来解决访问共享资源互斥的问题。全都转成了管道通信。
golang 这个模式叫做 CPS,有个类似的 Erlang 的 Actor.
这俩底层都是在多个核心上面跑的协程。
【 在 finlab 的大作中提到: 】
: 我理想的模型是,设法降低单个线程的开销,然后创建大规模的线程池。
: 就不用担心线程阻塞不够用。系统会简单很多。
: 叱滩痘瘛
: ...................
--
FROM 120.41.147.*
其实你们想的这些事情,几乎每个方案都有现实的例子。
比如 python 和 js 的协程就是不跨线程的。c++20 目前的几个实现应该也是不跨线程的。
而 c#, java, go 都是跨线程的。
只能说大家都活得不错。都有人用。各有优势劣势。没必要非彼即此。
【 在 ylh1969 的大作中提到: 】
: 不跨线程挺麻烦,跨线程反而简单。
--
修改:hgoldfish FROM 120.41.147.*
FROM 120.41.147.*
我觉得不是这样的呢。以前协程的使用成本比较高,需要修改引入第三方库。还有各种适配的 BUG。使用经验也不足。所以你看本版还在讨论协程该怎么用,要怎么实现这些事。
现在各种主流语言都标配协程了。后面大家会越用越熟练。直到最后,大家会发现所有函数指针、回调函数到最后都不必要的。那时系统架构与具体的编程细节都会迁移到协程架构来。
协程是一种新的架构。比如 Erlang 的 Actor, golang 的 CPS 都会对系统架构造成重大的冲击。
【 在 finlab 的大作中提到: 】
: 现在协程流行的原因,还是线程的成本太高。
: 一个是现在的cpu每个核心有独立缓存,一个线程固定分配到一个核心是最好的,如果线程反复随机调度到不同核心,就会导致缓存的效率大幅下降,
: 另一个是操作系统层面,线程是一个比较重的对象,操作系统支持的线程数量上限也不高。
: ...................
--
修改:hgoldfish FROM 27.154.110.*
FROM 27.154.110.*