- 主题:stackoverflow 有个比较 c++ stackful 和 stackless 协程的帖子
协程调度就是epoll呀!
主线程创建协程,丢进epoll。所有的线程都在epoll_wait,抓住哪个做哪个协程。协程在yield时,设置epoll,并swapcntext。线程继续epoll_wait。epoll激活这个协程后,由任何一个激活的线程进行resume。
整个的调度过程。
【 在 hgoldfish 的大作中提到: 】
: 一般协程库要三个部分:
: 1. 基础的协程切换,一般由语言库(c++ co_await)或者操作系统(swap_context)搞定
: 2. 事件循环以及协程调度(线程内与线程间调度)
: ...................
--
修改:ylh0315 FROM 221.218.61.*
FROM 221.218.61.*
主要是协程,在进行IO的超时,也包括在队列中等待的超时。
无论哪种超时,都可以在context数组中检测到。主线程负责这个检测。
【 在 hgoldfish 的大作中提到: 】
: 你又不是在多个线程间调度协程的超时。
: 话说,你可以参考一下操作系统的线程调度。因为你现在做的事情,已经相当于在 userland 自行实现了一份操作系统的内核线程调度了。
: 所以我有个观点是,能够实现协程调度的程序员,也必然有能力实现操作系统内核。
: ...................
--
修改:ylh0315 FROM 221.218.61.*
FROM 221.218.61.*
github打不开。
协程锁没有搞,暂时没有用到。
协程安全,主要就是线程锁不允许跨越IO(因为IO可能发生线程切换,函数返回就不是原来的线程了)。
【 在 hgoldfish 的大作中提到: 】
: 一般协程库要三个部分:
: 1. 基础的协程切换,一般由语言库(c++ co_await)或者操作系统(swap_context)搞定
: 2. 事件循环以及协程调度(线程内与线程间调度)
: ...................
--
FROM 221.218.61.*
就这么简单呀,线程从epoll里得到一个协程,就会一直运作下去,不需要调度,直到遇到IO不能完成,需要等待才进行yield(见84楼),协程丢进epoll队列,线程继续epoll_wait。
【 在 hgoldfish 的大作中提到: 】
: 没这么简单哦。。你可以参考一下 libgo 和 cppcoro 啊。看看它们是怎么实现协程版本的 mutex, timer 等等的。
:
--
修改:ylh0315 FROM 221.218.61.*
FROM 221.218.61.*
接115楼。
你可能会问,如果协程运行期间一直不调度(实际上就我这个交易管理器来说,不就是个消息转发吗?没啥工作量),别的任务怎么办呀?
别的任务有别的线程。有几个核就有几个线程(也可能多几个)。
所有线程都占满了呢?那就是达到了系统处理能力的极限了呗(应该可以看到CPU100%,实际见到过85%)。等不到服务的协程就在epoll里等着呗。
一般的交易虽说也是要求响应快,也没那么紧迫,耽误就耽误点。主要是别丢失交易和保证交易的完整性。
就如12306,迟钝就迟钝点,抢不到票就抢不到,有啥了不起。
如果发现处理能力吃紧,以后增加系统配置就得了。
【 在 hgoldfish 的大作中提到: 】
: 没这么简单哦。。你可以参考一下 libgo 和 cppcoro 啊。看看它们是怎么实现协程版本的 mutex, timer 等等的。
:
--
修改:ylh0315 FROM 221.218.61.*
FROM 221.218.61.*
感觉是GPS或者说北斗的交易,或者战场的战术数据链。你说的确实很对。这种场景还是别用协程了,不够耽误事的。
【 在 ziqin 的大作中提到: 】
: 说高频交易,要看是多高频
: 大家在抬杠过程中,总是说纳秒级,那我们就说纳秒级的tick to trade策略
: 交易所统计数据中,从新的tick发出,到收到下一次order flow的第一批高峰,大概是在16ns到500ns左右,这一批策略,基本上就是你说的,并发量在100(当然,对交易来说100也不小了)以内,因为基本上是一块芯片对一个合约,网卡收到交易所收到数据以后,所有的FIX解包就在网卡芯片上直接完成,然后的确是一个大的mesh,直接算出来,所有的策略参数,都是烧死在硬件里的,尽量减小动态读取的次数。这批头部玩家的主要区别其实是网线接在交易所路由器的第几个口,因为路由器背板转发事实上也是有先后的,能相差十几纳秒
: ...................
--
修改:ylh0315 FROM 221.218.61.*
FROM 221.218.61.*
不懂那么多理论。实际上大规模交易系统基本都是UNIX/LINUX。比较稳定可靠。WINDOWS?经常不稳定,也可能是用的不好。
【 在 leadu 的大作中提到: 】
: 不参与你们对协程的讨论,太蠢了
: 如果一个系统可以上通用os,windows有rio,intel抄了个半成品是dpdk,linux不会表现的比windows更好。
: 除非你裁剪linux内核,但都到了要裁剪内核的地步,我为啥不写点verilog直接fpga甚至asic搞定?
: ...................
--
FROM 221.218.61.*
是的,我也发现了。IBM的AIX也有IOCP系统。我说的这个东西也可以支持IOCP。
在yield的参数里增加两个:buffer,bytes 。
【 在 ensonmj 的大作中提到: 】
: linux是因为免费吧。在异步方面windows的iocp比epoll还是nb一点的,io_uring 的生态还差得远
--
修改:ylh0315 FROM 221.218.61.*
FROM 221.218.61.*
协程调度可以由epoll进行,基于如下特性:
1.事件fd直接绑定context,事件响应直接提供context。减少了一个根据fd查找context的过程。
2.任何线程可以在任何时候把fd和context投入epoll,并且立即生效,不需要另外的激活操作。这条决定了任何线程在任何时候对任何context执行“挂起”。
3.任何线程都可以进行epoll_wait,它守候的是所有的事件,而不仅是自己投入的那个。这就决定了,当线程把context投入epoll后,就可以为所有的事件fd服务,为任何context执行resume。实现了线程和协程之间的任务切换。
BSD的Kqueue也具有这些功能,也可以作为协程调度器。这种设计恰恰不是自己造轮子,完全就是使用系统轮子。
使用过libaio,异步文件读写,任务提交后,线程还要等待任务完成。撒不开手,期间不能切换任务。解决方法是,配个eventfd,连同context,丢进epoll,让它协助调度协程。
select,也凑合可以调度协程。
任何线程都可以设置efds,但是要激活一下守候线程。只有唯一一个线程可以守候select。
事件激活后,要查找是哪一个context。然后把context丢进一个队列,队列的另一端是很多个线程在守候,之后的过程就与epoll一样了。
现在我担心的是,IOCP,是否具备协程调度功能。
【 在 hgoldfish 的大作中提到: 】
: 没这么简单哦。。你可以参考一下 libgo 和 cppcoro 啊。看看它们是怎么实现协程版本的 mutex, timer 等等的。
:
--
修改:ylh0315 FROM 221.218.61.*
FROM 221.218.61.*
libaio没有协程调度功能,下述代码看到eventfd,协助任务调度,把efd放进yield,并投入epoll。当异步IO完成时,激活epoll,resume。
static int AIO_oper(int fd,char *buff,size_t iosize,int flg)
{
io_context_t myctx;
int rc,num;
uint64_t finished_aio;
struct iocb _iocb,*io=&_iocb;
struct io_event event;
int efd = eventfd(0, 0);
T_YIELD yield=get_yield();
if (efd == -1) {
return flg?write(fd,buff,iosize):read(fd,buff,iosize);
}
memset(&myctx,0,sizeof(myctx));
io_set_eventfd(io,efd);//绑定efd
io_queue_init(1, &myctx);
if(flg) io_prep_pread(io, fd, buff, iosize, 0);
else io_prep_pwrite(io, fd, buff, iosize, 0);
rc = io_submit(myctx, 1, &io);
if(rc<0) {
close(efd);
io_destroy(myctx);
return flg?write(fd,buff,iosize):read(fd,buff,iosize);
}
if(yield) {
rc = yield(efd,0,0);//把eventfd丢给epoll
if(rc==0) eventfd_read(efd, &finished_aio);
}
如果不是协程(没有yield),后边自己等待完成。
【 在 ylh0315 的大作中提到: 】
: 协程调度可以由epoll进行,基于如下特性:
: 1.事件fd直接绑定context,事件响应直接提供context。减少了一个根据fd查找context的过程。
: 2.任何线程可以在任何时候把fd和context投入epoll,并且立即生效,不需要另外的激活操作。
: ...................
--
修改:ylh0315 FROM 221.218.61.*
FROM 221.218.61.*