当前位置: 技术问答>linux和unix
[百度分享]用户态线程库 (三)
来源: 互联网 发布时间:2016-09-13
本文导语: 可控制的异步调用 在用户态的线程库中,我们可以采用同步思维方式写出等价于异步效果的程序,并且在性能提升方面占有一定的优势. 一方面可以付出一定的内存开销(异步条件上下文完全通过内存池维护空间会小一些)开辟...
可控制的异步调用
在用户态的线程库中,我们可以采用同步思维方式写出等价于异步效果的程序,并且在性能提升方面占有一定的优势.
一方面可以付出一定的内存开销(异步条件上下文完全通过内存池维护空间会小一些)开辟出更多的线程(几十W级别规模), 另一方面编程模式不会发生太大的改变
计算异步化
这里主要是考虑,类似 GPU或者数据压缩卡这样的计算模式, 将一部分的计算拿出去进行计算, CPU可以继续进行其他工作,从而短时间内处理更多的工作。
网络IO异步化
网络IO的一个特点就是在多路复用的情况下占有一定的优势, 可以不用大量的select时间来等待IO可读可写。在协程中如果仅仅是简单的采用我们的同步IO 会给程序带来灾难。 出现前面提到的 快速的程序越快,慢的程序越慢,响应事件时间的差距变大
1 do { 2 //非堵塞读数据 3 if (数据没有读完) { 4 yield() 5 } 6 while (
7 //数据没读完 8 ) 9 //切换后10 //epoll_wait 等待句柄激活11 //激活的调度12 if (fd 激活) {13 //上下文件切换到 fd对应的地方运行14 }
磁盘IO异步化
与网络IO有所不同, 磁盘IO有一定的特殊性
多线程的同时写不能有效的提高写的速度,无论是否使用dio
多线程读磁盘, 由于受到缓存,电梯调度的一些影响, 往往是可以有一定提高的。
多线程读写的情况下往往会用 pwrite, pread 来指定写的位置, 除非是不关心顺序问题
针对这几点,在处理上可以采用下面的方式
对于真正的IO读取任务,调用较多的真实线程来处理, 而对于写IO, 相同的fd 可以集中处理,甚至是在最后写的时候统一采用writev机制。
这里包括几个方面
1 while (task_q.empyt()) { 2 3 task = task_q.pop() 4 if (task 是写IO) { 5 //量小可以不切换直接当场处理 6 //task 按照fd 取mod 放入 磁盘写处理线程 7 //获取管道,监听成功结果 8 } 9 10 if (task 是读IO) {11 //task 放入 磁盘读处理线程12 //获取管道,监听成功结果13 }14 }
IO写
1 foreach fd {2 foreach pwrite fd {3 //判断是否有连续的,如果存在可以减少调用4 }5 foreach write fd {6 //一次writev操作7 }8 9 }
IO读也是类似的
1 foreach fd { 2 foreach pread fd { 3 //判断是否有连续的,如果存在可以减少调用 4 } 5 6 foreach read fd { 7 //一次readv操作 8 } 9 }
这里只是简单的考虑磁盘IO在协程条件下的处理考虑, 这里IO也是作为一种调度策略存在。 如果是SSD硬盘, 可能更多情况下不需要调度直接处理更合适。
应用上的考虑
框架层面上的支持
在ub这样的编程框架中支持, 通过配置进行切换, 直接在同步模型下进行替换.只不过这里需要通过IO函数替换来实现
比如:
ul_sreado_ex2 需要改造成下面的样子:
1 do {2 //非堵塞读数据3 if (
4 //数据没有读完
5 ) {6 yield()7 }8 while (
9 //数据没读完
10 )
通过对于这些函数的替换基本就可以实现同步IO想异步IO的切换,从而表现出现异步的样子.
另外一种方式就是直接替换系统调用,让用户无缝升级, 最简单的方式就是直接替换glibc中的对应的函数接口。但这种接管的代价会比较大,而且容易出错。
在用户态的线程库中,我们可以采用同步思维方式写出等价于异步效果的程序,并且在性能提升方面占有一定的优势.
一方面可以付出一定的内存开销(异步条件上下文完全通过内存池维护空间会小一些)开辟出更多的线程(几十W级别规模), 另一方面编程模式不会发生太大的改变
计算异步化
这里主要是考虑,类似 GPU或者数据压缩卡这样的计算模式, 将一部分的计算拿出去进行计算, CPU可以继续进行其他工作,从而短时间内处理更多的工作。
网络IO异步化
网络IO的一个特点就是在多路复用的情况下占有一定的优势, 可以不用大量的select时间来等待IO可读可写。在协程中如果仅仅是简单的采用我们的同步IO 会给程序带来灾难。 出现前面提到的 快速的程序越快,慢的程序越慢,响应事件时间的差距变大
1 do { 2 //非堵塞读数据 3 if (数据没有读完) { 4 yield() 5 } 6 while (
7 //数据没读完 8 ) 9 //切换后10 //epoll_wait 等待句柄激活11 //激活的调度12 if (fd 激活) {13 //上下文件切换到 fd对应的地方运行14 }
磁盘IO异步化
与网络IO有所不同, 磁盘IO有一定的特殊性
多线程的同时写不能有效的提高写的速度,无论是否使用dio
多线程读磁盘, 由于受到缓存,电梯调度的一些影响, 往往是可以有一定提高的。
多线程读写的情况下往往会用 pwrite, pread 来指定写的位置, 除非是不关心顺序问题
针对这几点,在处理上可以采用下面的方式
对于真正的IO读取任务,调用较多的真实线程来处理, 而对于写IO, 相同的fd 可以集中处理,甚至是在最后写的时候统一采用writev机制。
这里包括几个方面
1 while (task_q.empyt()) { 2 3 task = task_q.pop() 4 if (task 是写IO) { 5 //量小可以不切换直接当场处理 6 //task 按照fd 取mod 放入 磁盘写处理线程 7 //获取管道,监听成功结果 8 } 9 10 if (task 是读IO) {11 //task 放入 磁盘读处理线程12 //获取管道,监听成功结果13 }14 }
IO写
1 foreach fd {2 foreach pwrite fd {3 //判断是否有连续的,如果存在可以减少调用4 }5 foreach write fd {6 //一次writev操作7 }8 9 }
IO读也是类似的
1 foreach fd { 2 foreach pread fd { 3 //判断是否有连续的,如果存在可以减少调用 4 } 5 6 foreach read fd { 7 //一次readv操作 8 } 9 }
这里只是简单的考虑磁盘IO在协程条件下的处理考虑, 这里IO也是作为一种调度策略存在。 如果是SSD硬盘, 可能更多情况下不需要调度直接处理更合适。
应用上的考虑
框架层面上的支持
在ub这样的编程框架中支持, 通过配置进行切换, 直接在同步模型下进行替换.只不过这里需要通过IO函数替换来实现
比如:
ul_sreado_ex2 需要改造成下面的样子:
1 do {2 //非堵塞读数据3 if (
4 //数据没有读完
5 ) {6 yield()7 }8 while (
9 //数据没读完
10 )
通过对于这些函数的替换基本就可以实现同步IO想异步IO的切换,从而表现出现异步的样子.
另外一种方式就是直接替换系统调用,让用户无缝升级, 最简单的方式就是直接替换glibc中的对应的函数接口。但这种接管的代价会比较大,而且容易出错。
|
名人的技术分享都木人顶
|
CSDN可耻的跟百毒这垃圾玩意合作了吗?
|
顶 顶
结帖率:0.00% ????
结帖率:0.00% ????
|
看看先