基本思路是,把 IO 操作(通常是写操作)通过 BlockingQueue 交给别的线程去做,自己不必等待。

例1: logging

在多线程服务器程序中,日志 (logging) 至关重要,本例仅考虑写 log file 的情况,不考虑 log server。

在一次请求响应中,可能要写多条日志消息,而如果用同步的方式写文件(fprintf 或 fwrite),多半会降低性能,因为:

  • 文件操作一般比较慢,服务线程会等在 IO 上,让 CPU 闲置,增加响应时间。
  • 就算有 buffer,还是不灵。多个线程一起写,为了不至于把 buffer 写错乱,往往要加锁。这会让服务线程互相等待,降低并发度。(同时用多个 log 文件不是办法,除非你有多个磁盘,且保证 log files 分散在不同的磁盘上,否则还是受到磁盘 IO 瓶颈制约。)

解决办法是单独用一个 logging 线程,负责写磁盘文件,通过一个或多个 BlockingQueue 对外提供接口。别的线程要写日志的时候,先把消息(字符串)准备好,然后往 queue 里一塞就行,基本不用等待。这样服务线程的计算就和 logging 线程的磁盘 IO 相互重叠,降低了服务线程的响应时间。

尽管 logging 很重要,但它不是程序的主要逻辑,因此对程序的结构影响越小越好,最好能简单到如同一条 printf 语句,且不用担心其他性能开销,而一个好的多线程异步 logging 库能帮我们做到这一点。(Apache 的 log4cxx 和 log4j 都支持 AsyncAppender 这种异步 logging 方式。)

例2: memcached 客户端

假设我们用 memcached 来保存用户最后发帖的时间,那么每次响应用户发帖的请求时,程序里要去设置一下 memcached 里的值。这一步如果用同步 IO,会增加延迟。

对于“设置一个值”这样的 write-only idempotent 操作,我们其实不用等 memcached 返回操作结果,这里也不用在乎 set 操作失败,那么可以借助多线程来降低响应延迟。比方说我们可以写一个多线程版的 memcached 的客户端,对于 set 操作,调用方只要把 key 和 value 准备好,调用一下 asyncSet() 函数,把数据往 BlockingQueue 上一放就能立即返回,延迟很小。剩下的时就留给 memcached 客户端的线程去操心,而服务线程不受阻碍。

其实所有的网络写操作都可以这么异步地做,不过这也有一个缺点,那就是每次 asyncWrite 都要在线程间传递数据,其实如果 TCP 缓冲区是空的,我们可以在本线程写完,不用劳烦专门的 IO 线程。Jboss 的 Netty 就使用了这个办法来进一步降低延迟。

以上都仅讨论了“打一枪就跑”的情况,如果是一问一答,比如从 memcached 取一个值,那么“重叠 IO”并不能降低响应时间,因为你无论如何要等 memcached 的回复。这时我们可以用别的方式来提高并发度,见问题8。(虽然不能降低响应时间,但也不要浪费线程在空等上,对吧)

另外以上的例子也说明,BlockingQueue 是构建多线程程序的利器。

5. 多线程程序如何让 IO 和“计算”相互重叠,降低 latency?相关推荐

  1. 对多线程程序,单核cpu与多核cpu如何工作相关的探讨

    对多线程程序,单核cpu与多核cpu如何工作相关的探讨 我们程序员在编码的时候,涉及到技术方案时,往往会忽略掉代码对性能方面的影响,或者没有足够的敏感度来帮助自己判断自己的技术方案对系统性能造成的影响 ...

  2. 对于多线程程序,单核cpu与多核cpu是怎么工作的

    此文中的大部分资料来自于网络上,我只是觉得把有道理的整理一下,方便以后查阅. 1.多线程在单核和多核CPU上的执行效率问题的讨论 a1: 多线程在单cpu中其实也是顺序执行的,不过系统可以帮你切换那个 ...

  3. 通过java.util.concurrent写多线程程序

    在JDK 1.5之前,要实现多线程的功能,得用到Thread这个类,通过这个类设计多线程程序,需要考虑性能,死锁,资源等很多因素,一句话,就是相当麻烦,而且很容易出问题.所幸的是,在JDK1.5之后, ...

  4. [C++11 std::thread] 使用C++11 编写 Linux 多线程程序

    From: http://www.ibm.com/developerworks/cn/linux/1412_zhupx_thread/index.html 本文讲述了如何使用 C++11 编写 Lin ...

  5. JAVA多线程程序ProgressBar

    JAVA多线程程序ProgressBar 题目简介: 思维导图: 实验代码:建议先看CalThread类,计算线程的实现,再作基本CalFrame类的界面, 然后作ReadThread类,结合CalF ...

  6. Linux多线程实践(10) --使用 C++11 编写 Linux 多线程程序

    在这个多核时代,如何充分利用每个 CPU 内核是一个绕不开的话题,从需要为成千上万的用户同时提供服务的服务端应用程序,到需要同时打开十几个页面,每个页面都有几十上百个链接的 web 浏览器应用程序,从 ...

  7. c语言如何多核运行程序,对于多线程程序,单核cpu和多核cpu如何工作?

    1. 单核和多核CPU上多线程执行效率的探讨 a1: 多线程实际上是在单个CPU中按顺序执行的,但是系统可以帮助您切换该执行,但是它不是很快的(相反,是缓慢的) 如果有多个cpus,则可以同时在两个c ...

  8. JAVA程序中怎么看线程的个数_一个文件中有10000个数,用Java实现一个多线程程序将这...

    18 推荐 运行结果: 编辑于 2015-07-16 17:20:57 回复(11) 12 自己重写了一下推荐答案,加了些注释方便理解 package threadpackage; import ja ...

  9. C++核心准则CP.1: 设想你的代码​会成为多线程程序的一部分

    CP.1: Assume that your code will run as part of a multi-threaded program CP.1: 设想你的代码会成为多线程程序的一部分 Re ...

最新文章

  1. 怎么修改CAD编辑器中默认的线型
  2. 计算机办公应用适合什么工作,有什么软件堪称办公神器,让你每天的工作轻松不累?...
  3. 通过一个例子学习Kubernetes里的PersistentVolumeClaim的用法
  4. 文秘专业计算机基础考题,《计算机应用基础》课程无纸化试题库建设及应用分析...
  5. 怎么测试ajax get请求,为什么我的AJAX在运行测试时请求dev中的PUT请求,但请求了GET请求?...
  6. 2018-6-19bash编程之循环
  7. 进程树--用Enki学Linux系列(18)
  8. 堆内存与栈内存能不能共享,不能,,通俗的比较,堆主要用来存放对象的,栈主要是用来执行程序的...
  9. 《游戏设计师修炼之道:数据驱动的游戏设计》一1.4 来自政府和产业的挑战...
  10. NV12图像格式叠加(水印原理演示)
  11. 利用easyCHM制作JavaAPI帮助文档
  12. linux安装vsftpd并配置文件,Linux 系统下 vsftpd 的安装与配置
  13. Spring:Spring支持的bean作用域有哪些
  14. 苹果台式电脑怎么使用计算机,苹果笔记本键盘怎么用_苹果笔记本电脑键盘的使用方法-win7之家...
  15. 苹果平板重设id显示服务器出错,苹果一代平板电脑重设ID怎么?
  16. Liu C-2021-1: Nontrivial Gates FET
  17. pli测试50题题库_【马士基销售代表面试】性格测试+12分钟50道题。-看准网
  18. 组播IGMP 自学笔记
  19. 如何用python写脚本_python写脚本
  20. 我从外包公司离职了(一定要看 防坑指南)!

热门文章

  1. numpy 平方_NumPy入门指南
  2. php dump utfp,php pchart乱码-使用REST接口获取GeoServer中的...-结合 thinkPHP 分页写成自己分页类_169IT.COM...
  3. u盘安装linux 提示no such device_Linux 网络基础设计
  4. bigdecimal判断等于0_vue2.0源码用到的工具函数,12个简易的复用函数,看看有多简单...
  5. Android代码数字证书,有关Android中读取证书
  6. 什么是工业光纤收发器,工业收发器的作用是什么?
  7. 关于交换机和路由器的区别介绍
  8. 采购光纤收发器时应该注意哪些事项?
  9. [渝粤教育] 西南科技大学 线性代数 在线考试复习资料
  10. [渝粤教育] 西南科技大学 中国现代文学 在线考试复习资料