《代码整洁之道》—第13章13.1节为什么要并发

  1. 云栖社区>
  2. 博客>
  3. 正文

《代码整洁之道》—第13章13.1节为什么要并发

异步社区 2017-05-02 10:09:00 浏览1041
展开阅读全文

本节书摘来自异步社区《代码整洁之道》一书中的第13章13.1节为什么要并发,作者【美】Robert C. Martin,更多章节内容可以访问云栖社区“异步社区”公众号查看。

第13章 并发编程
代码整洁之道
Brett L.Schuchert


9a4d662ae3d62b1c0b244cf2eda6b16cee29b1aa

“对象是过程的抽象。线程是调度的抽象。”

——James O Coplien[1]

编写整洁的并发程序很难——非常难。编写在单线程中执行的代码简单得多。编写表面上看来不错、深入进去却支离破碎的多线程代码也简单。系统一旦遭受压力,这种代码就扛不住了。

本章将讨论并发编程的需求及其困难之处,并给出一些对付这些难点、编写整洁的并发代码的建议。最后,我们将讨论与测试并发代码有关的问题。

整洁的并发编程是个复杂话题,值得用一整本书来讨论。本书只做概览,并在“并发编程II”一章中提供更详细的指引。如果你只是对并发好奇,阅读本章就足够了。如果你需要更深入地理解并发,就应读完整个指引章节。

13.1 为什么要并发
并发是一种解耦策略。它帮助我们把做什么(目的)和何时(时机)做分解开。在单线程应用中,目的与时机紧密耦合,很多时候只要查看堆栈追踪即可断定应用程序的状态。调试这种系统的程序员可以设定断点或者断点序列,通过查看到达哪个断点来了解系统状态。

解耦目的与时机能明显地改进应用程序的吞吐量和结构。从结构的角度来看,应用程序看起来更像是许多台协同工作的计算机,而不是一个大循环。系统因此会更易于被理解,给出了许多切分关注面的有力手段。

例如,Web应用的Servlet标准模式。这类系统运行于Web或EJB容器的保护伞之下,Web或EJB为你部分地处理并发问题。当有Web请求时,servlet就会异步执行。Servlet程序员无需管理所有的请求。原则上,每次servlet是在自己的小世界中执行,与其他servlet的执行是分离的。

当然,如果只是那么简单,也就没必要写这一章了。实际上,Web容器提供的解耦手段离完美还差得远。Servlet程序员得非常警惕、非常小心地保证并发程序不出错。同样,servlet模式的结构性好处还是很明显。

但结构并非采用并发的唯一动机。有些系统对响应时间和吞吐量有要求,需要手工编写并发解决方案。例如,考虑一个单线程信息聚合程序,它从许多Web站点获取信息,再合并写入日志中。因为该系统是单线程的,它会逐个访问Web站点,在开始下一个之前等待当前站点访问完毕。每天的执行时间必须少于24个小时。然而,随着要访问的站点越来越多,采集所有数据花费的时间也越来越多,最终超过了24个小时的限制。单线程程序许多时间花在等待Web套接字I/O结束上面。通过采用同时访问多个站点的多线程算法,就能改进性能。

或者,考虑某个每次花费1秒钟处理一个用户请求的系统。该系统在用户量较少的时候响应及时,但随着用户数增加,系统的响应时间也增加了。没人想排在150个人后面!通过并发处理多个用户请求,就能改进系统响应时间。

再或者,考虑某个解释大量数据集、但只在处理完全部数据后给出一个完整解决方案的系统。或许可以在独立的计算机上处理每个数据集,那样的话许多数据集就能并行地得到处理。

迷思与误解
看来有足够的理由采用并发方案。然而,如前文所述,并发编程很难。如果你不那么细心,就会搞出不堪入目的东西来。看看以下常见的迷思和误解:

(1)并发总能改进性能

并发有时能改进性能,但只在多个线程或处理器之间能分享大量等待时间的时候管用。事情没那么简单。

(2)编写并发程序无需修改设计

事实上,并发算法的设计有可能与单线程系统的设计极不相同。目的与时机的解耦往往对系统结构产生巨大影响。

(3)在采用Web或EJB容器的时候,理解并发问题并不重要

实际上,你最好了解容器在做什么,了解如何对付本章后文将提到的并发更新、死锁等问题。

下面是一些有关编写并发软件的中肯说法:

并发会在性能和编写额外代码上增加一些开销;
正确的并发是复杂的,即便对于简单的问题也是如此;
并发缺陷并非总能重现,所以常被看做偶发事件[2]而忽略,未被当做真的缺陷看待;
并发常常需要对设计策略的根本性修改。

网友评论

登录后评论
0/500
评论
异步社区
+ 关注