1.1 历史起源
人类经常有建造新的宏伟项目的想法,超越所有之前的伟大项目。吉萨的大金字塔是最大的,迪拜的哈利法塔是最高的,而长城则是最长的。
然而,组织这些项目的工作非常困难。如果要建造一个高出两倍的新金字塔,它将需要八倍于之前的石料。这意味着我们要么提高采石场的产量,要么开设更多的采石场。
我们还需要找到多达八倍的工程师,可能要开设工程学校,标准化图纸、几何和文字。总之,这是一项艰巨的任务...
从建造金字塔至今几千年过去了,但真没什么变化,人们依旧在思考如何用更少的时间完成更多的工作。当计算机被发明出来时,这个问题吸引了人类最聪明的大脑。
如何让程序跑得快十倍?这个问题看似很奇怪——如果处理器已经在最大速度运行了,那可能无解。然而我提到的聪明大脑,他们分析了所有程序的运作得出结论:有三个主要方向可以提升。
消除闲置
原来大部分时间程序都在闲置。程序不断在等待:数据需要从一个内存位置复制到另一个,从硬盘加载到内存,等待服务器响应请求,等待用户输入等。
所有这些任务并不是由中央处理器完成的,而是由内存、磁盘之类的控制器完成。而中央处理器这时可以用来做一些有用的事情。这就诞生了在一个处理器中运行多个执行线程(thread)的想法。
例如,当一个线程等待用户输入时,第二个线程可以通过网络下载东西,第三个线程处理数据,第四个线程向屏幕绘制图像。然后这个任务进化成异步任务和协程,但我们以后再讨论这个。
更多程序
如果程序80%的时间都在闲置,那当然不太好。不过,从另一面来讲,我们不可能根据新的方法重写所有的程序。或许可以通过其他方式解决这个问题——就是在计算机上同时运行多个程序。
在这种情况下,操作系统监控程序的运作,如果程序闲置,会把它的执行时间给其他程序。这样的切换每秒钟发生几十次,用户几乎没发觉——在他看来,程序是同时执行的。
更多处理器
同时执行程序是很棒的,但如果程序很多,又几乎不闲置呢?没有闲置就没有高效利用。比如,我们有十个程序在计算,或者是有一个资源密集型游戏和其他的程序一起运行。
解决这个问题的方法是往处理器里面加多个处理器。为了避免混淆,这些被称为核心。现在,我们有的处理器有多个内核(子处理器),上面同时运行着几十个程序。
有意思的事情!处理器中的核心数量
现在的服务器处理器可以有64到256个核心,在一些特定场景下甚至更多。例如,AMD EPYC第四代处理器可以提供多达96个核心,而IBM POWER10则可以在芯片上拥有240个核心。用户级的处理器也有了很大发展:像AMD Threadripper这样的高性能桌面CPU可以有多达64个核心,而更常见的型号通常有6到16个核心。
那么未来会怎样呢?当然有发展空间!首先,一块服务器主板上可以安装多个处理器,比如两个甚至四个。其次,服务器可以组成服务器机架,一架有10到20台。服务器机架又可以组成数据中心,那里有成千的机架。
分布式系统和微服务架构已经成为现代软件开发中的常见实践。许多大公司,比如Google、Amazon、Netflix,甚至一些较小的公司,都使用分布式系统来处理大量数据,确保服务的高可用性和可扩展性。这些系统使得我们可以有效利用多个服务器的资源,像一个整体一样工作,显著提高了应用程序的性能和抗故障能力。
1.2 优势
多线程,或者程序内部任务的同时执行,提供了几个关键优势,能够显著提升软件的性能和效率。下面我们来看看多线程的主要优势。
1. 提高性能和执行速度
并行执行任务:多线程允许同时执行多个任务,这对于需要进行许多独立操作的程序特别有用。这可以加快程序的执行,因为任务是并行执行的,利用所有可用的处理器资源。
使用多核处理器:现代处理器有多个核,多线程可以通过在不同核上分配线程来完全利用它们的能力,从而并行执行任务。
2. 改善与用户互动的响应性
后台任务:多线程可以在后台执行耗时或资源密集型操作,同时保持负责用户界面的主线程响应良好。这改善了用户体验,因为界面在执行繁重任务时不会被阻塞。
异步操作:用户交互和事件处理可以与主任务的执行并行进行,这使得应用程序更加响应迅速和高效。
3. 高效利用系统资源
资源优化:多线程可以更有效地利用系统资源,比如处理器时间和内存。这对于服务器和高性能计算系统特别重要,在这些系统中,多线程可以同时处理大量请求和任务。
输入/输出管理:多线程应用可以更高效地管理输入/输出任务(例如网络操作、文件读写),因为线程可以在等待I/O操作完成时执行其他任务。
4. 支持多任务处理
多任务处理:多线程允许在一个进程内同时执行多个任务,这简化了需要多任务的应用程序的开发,例如Web服务器、数据库和实时应用。
数据并行处理:在涉及大规模数据处理的任务中,多线程允许将数据分成部分并行处理,显著加快任务执行。
多线程的应用实例
Web服务器:多线程让Web服务器可以同时处理大量的客户端请求,提高服务器的性能和可扩展性。
图形用户界面(GUI):在具有图形界面的应用中,多线程可以在后台执行长时间计算,保持界面响应性。
科学计算:多线程用于科学计算中的数据并行处理,加快复杂计算任务的执行。
游戏与模拟:在游戏中,多线程可以同时处理物理、图形、声音和用户操作,提高性能和逼真度。
1.3 正确的命名
«多线程»这个名字有些问题。它由两个词组成:「多」和「线程」,似乎暗示程序内部有很多「指令执行线程」在运行。
这个比喻很美,但在英文(原版)文献中,描述并行执行的动作用的词是“thread”。因此,多线程在英文中是 multi-threading。
这可以算作小误会——不同语言的术语翻译谁在乎呢,如果不是编程中开始广泛使用了一个叫 stream 的东西,除了用«流»这个词,没法翻译。
因此,现在的俄语术语中存在一些混乱,解决方法有两个:
- 把
Thread(线程)翻译成「指令执行流」。 Stream(流)翻译为「数据流」。
另一方面,许多程序员直接使用英文术语:
- 把
Thread(线程)叫作「thr」とmulti-threading叫作「multi-threading」。 Stream(流)叫作「stream」。
Thread经常被叫作线程,但「多线程化」这个词却并没有流行。因此,人们常在对话中同时使用「线程」和「多线程」。
使用大量外来术语让语言更丰富,赋予单词新含义,简化与其他国家同事的交流。我完全支持这种方法。
GO TO FULL VERSION