- 主题:觉得协程不是一个太好的编程模型
这就是典型的卖火车票嘛!
选定的车票在数据库被标定为占用,等待你的支付成功的消息,跟线程协程没关系。
倒是支付等待回执,确实是个协程,它仅仅就是调用一个RecvNet(),在有协程之前,它会锁定一个线程,直到银行回复。在改成协程之后,中途会yield,会动用epoll,有回复就会resume,一切是透明的,业务软件没有任何的修改。
【 在 hgoldfish 的大作中提到: 】
: 如果一个业务是异步的,那么它的异步是无法消除的。
: 比如,你向银行发送了一个汇款申请。但是啥时候真的完成汇款,这是异步的。类似的还有网络请求。发送任务,然后等远程执行完毕,再继续本地下一步的动作。这样的场景在 GUI 编程混合网络请求时特别常见。
: 好了。我们现在再来考虑,要实现异步的业务,应该用哪一种技术呢?
: ...................
--
修改:ylh1969 FROM 221.218.60.*
FROM 221.218.60.*
协程避免了callback。
我记得callback是叫continueation模式。
【 在 overcomeunic 的大作中提到: 】
: 各种callback吧
: callback也很麻烦,层次深了没法看
: coroutine是不是还需要点时间才能真的跟 thread顶掉pthread 一样呀
--
FROM 221.218.60.*
我好像就是这个需求,就那么实现了。
【 在 VincentGe 的大作中提到: 】
: 其实也算
: 协程是语言层面的,和线程的比较只能说大部分情况下,协程是并发,线程是并行
: 其实你说的这个更对应异步任务的概念,这里线程是一个调度器。
: ...................
--
FROM 221.218.60.*
看76楼。协程避免了callback,那个接收函数,里边做点手脚就可以yield,外边的应用不需要改变,也不需要callback啥的。
【 在 overcomeunic 的大作中提到: 】
: 各种callback吧
: callback也很麻烦,层次深了没法看
: coroutine是不是还需要点时间才能真的跟 thread顶掉pthread 一样呀
--
FROM 221.218.60.*
看76楼,应用调用了接收函数,是个通用函数,单任务,多进程,多线程,线程池模式都是调用这个函数,应用程序(插件)根本就不知道任何的模式。
在前三个模式下,当调用这个函数时,的确陷入更待,直到银行回复,或超时,没啥问题。
但是在线程池模式下,几个这样的任务就把线程耗尽。
会要求应用软件按照异步模式修改代码吗?考虑过,有点难。
于是,有了协程,在那个函数内部,判断是协程环境,就以NONBLOCK方式接收消息,没有消息就yield。把协程的context排入epoll(事件管理器),释放线程。等银行那边有消息了,epoll会把这个context激活,交给一个线程,线程会resume回来,继续未完的接收。直到任务完成,接收函数正常返回,该函数的使用,没有任何变化,基本不需要修改用户程序。
这个过程说明,异步过程,进行两次协程切换和一组epoll的排队和激活过程,开销比同步过程大太多了,还没说其中还要写好些日志。
因此说协程是为了减小切换开销是不对的,我这里凭空增加了大量开销。
【 在 finlab 的大作中提到: 】
: 协程很多场合是为了节省线程切换的成本,提高cpu的利用率。
: 但是经常把一个事情劈成两半,绕了半天还是要再捏到一起。
: 既然协程这么流行,那就不如在cpu和操作系统、编译器层面进行优化,
: ...................
--
修改:ylh1969 FROM 221.218.60.*
FROM 221.218.60.*
76楼看看
举个例子:
SendNet("支付请求信息”);
RecvNet("银行回复");
这个接收,你不知道银行何时能回复,线程一直在等。
你的线程池,没几个线程,业务忙了,马上卡死。
你让业务逻辑自己去玩异步IO?
你跟我说过上层底层要隔离,我说也是,只能底层函数改造,让用户的同步调用不变,底层异步化,这就是同步调用异步化。使用的工具就是协程。具体办法就是在里边写yield。
前边哥们说的协程原语,我理解应用应该这么写:
await bankback
是省事,但是也需要修改应用程序,隔离度不好。
因为我是多进程,多线程,线程池一路走来,到了这一步,出了问题,才祭出了协程,所以直接就搞多线程协程,这样修改最少。
最早的需求就是同步调用异步化,至少讨论了两年,也做过其他尝试,如continueation模式,就是callback模式,不理想,最后找到协程。
【 在 VincentGe 的大作中提到: 】
: 我有个疑惑,单线程我理解,但为什么多进程,多线程,线程池会阻塞?
: 是不是你等这个线程中的任务完成?
:
: ...................
--
修改:ylh1969 FROM 221.218.60.*
FROM 221.218.60.*
是。我做的就是工具代码,与任何业务代码隔离。业务人员也无需理解。他们只需要使用RecvNet()取得信息就行了。完全不需要知道什么线程协程,什么同步异步。
【 在 VincentGe 的大作中提到: 】
: 我的意思是,对于你的业务代码,应该尽可能简单,抽象,易于理解,最好符合人的心智模型,业务人员也应该可以理解。
: 如果你在你的业务代码中混入协程,多线程代码,你的代码会变得非常难以理解,既然如此,你为什么不设计一个dsl,再实现一个执行器,这样,你不就成功实现了业务和实现的解耦?
:
: ...................
--
FROM 221.218.60.*
是在多线程模型里混入协程。
线程池本来就有调度器,没事时都在调度器里待着。
混入协程,线程自己也有一个context。从调度器得到一个任务,就swapcontext,进行一次切换进入协程。运行到需要yield,就再一次切换,回到自己的context,继续在调度器里等待。每个协程的一次执行需要两次切换。
这个过程与任何业务逻辑无关,业务人员不需要了解这些。
前边等银行回应的例子,还有等身份证回应的,等其他任何外部事务回应的,都让他们自己写异步等待,几乎是不可能的事。所有这些,使用RecvNet()就好了。
并行处理会有一个管理器,把业务分解成多个独立部分,这些独立的数据发送给调度器,每一个批次分配给一个线程。通过socket,调度器就是epoll。
【 在 VincentGe 的大作中提到: 】
: 这个复杂性在我看来更多是使用者带来的。
: 你难道要在一个协程中使用多线程模型吗?
:
: ...................
--
修改:ylh1969 FROM 221.218.60.*
FROM 221.218.60.*