Kqueue和其他的多路复用IO的核心是,单消费者同时监听不同种类的生产者,从而提供高性能的单线程IO,减少调度开销 。而Kqueue通过在内核态维持状态提供了更高的性能 。
生产者消费者模型
文章插图
单Producer和单Consumer
生产者/消费者模型是常见的通信模型,通过共享内核缓冲区环形队列,实现异步的事件通知 。双方只关注缓冲区内的数据,而不关注彼此,因此常常被用于网络通信 。
信号量
为了避免消费者在缓存区未满时无意义的轮询,消费者block直到生产者通知 。wait时线程设置信号量并且block,notify时内核通知所有等待信号的线程状态改为RUNNABLE 。
事实上就是linux的pthread_cond_wait和phread_cond_signal原语 。consumer之所以要带锁wait,是因为在内部进行调度yield_wait前要放掉锁,否则其他线程无法进入临界区;唤醒之后重新获得锁 。(这里指的锁是外部事务的锁)
wait和notify需要增加锁,防止notify先于wait进行 。(这里的锁指的是内部事务的锁)
wait调用的yield_wait在调度时需要临时释放并随后获取内部事务锁,否则会阻塞其他的notify造成全员block 。
send(bb, msg):acquire(bb.lock)while True:if bb.in - bb.out < N:bb.buf[bb.in mod N] <- msgbb.in <- bb.in + 1release(bb.lock)notify(bb.not_empty)returnwait(bb.not_full, bb.block) receive(bb):acquire(bb.lock)while True:if bb.in > bb.out:msg <- bb.buf[bb.out mod N]bb.out <- bb.out + 1release(bb.lock)wait(bb.not_full)returnwait(bb.not_empty, bb.block)
Eventcount & Sequencer这是1979年提出的算法,作为信号量的可替换实现 。Sequencer的目的是处理多producer 。
semaphores
send(Buffer& buffer,Message msg) {t=TICKET(T);AWAIT(buffer.in, t);AWAIT(buffer.out, READ(buffer.in)-N);buffer[READ(buffer.in)%N]=msg;ADVANCE(in);}receive(Buffer& buffer) { AWAIT(buffer.in, READ(buffer.out)); msg = buffer[READ(buffer.out)%N]; ADVANCE(buffer.out); return msg;}
- AWAIT(event*,val) - 比较event.count和val,如果大于则返回,否则存入线程TCB并yield
- ADVANCE(event*) - 自增event.count并将所有同event且event.count>val的线程唤醒
- TICKET(sequencer*) - 原子性自增序号,目的是处理并发的sender
- READ(event*) - 原子性读event.count,因为可能读操作涉及多memory cell
【单线程性能秒杀多线程!多路复用IO实现高性能网络服务】receive等待缓冲区存在数据时读取数据 。
推荐阅读
- 淘宝影响客单价的因素有哪些 淘宝如何提高客单价
- 天猫店铺可以修改订单价格吗 淘宝卖家怎么修改订单价格
- 淘宝店铺订单改价为什么改不了 手机淘宝怎样提交订单改价
- 招聘|这个编制单位4月中旬公开招聘,年收入可达12万,专科生也能报名
- 事业单位|这一事业单位开始招聘,虽不起眼但月薪过万,双休没有kpi压力
- 淘宝订单险开通好还是不开通好 淘宝卖家订单险有必要开通吗
- 淘宝订单险开通好还是不开通好 淘宝卖家开通订单险有什么用
- 代运营怎么判定诈骗怎么办 淘宝代运营诈骗是属于单位犯罪吗
- 茶与唐诗宋词介绍,简单介绍眉茶的品种分类
- 查真假烟最简单方法是什么?