数字营销 · Web开发 · 基础设施

线程和进程的比较之我见

用程序执行和麦当劳窗口的例子,通俗理解进程与线程的概念,以及 Python 中一个进程运行多个线程的方法。

在程序猿的世界中,线程和进程是一个非常重要的概念。很多人经常弄不清楚线程和进程到底是什么,以及它们之间有什么区别。本文就试图用比较容易理解的方式来解释一下线程和进程。

首先来看一下概念。

进程(英语:process),是计算机中已运行程序的实体。进程为曾经是分时系统的基本运作单位。在面向进程设计的系统(如早期的 UNIX、Linux 2.4 及更早的版本)中,进程是程序的基本执行实体;在面向线程设计的系统(如当代多数操作系统、Linux 2.6 及更新的版本)中,进程本身不是基本运行单位,而是线程的容器。程序本身只是指令、数据及其组织形式的描述,进程才是程序真正的运行实例。——维基百科

线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程执行不同的任务。——维基百科

这些概念看起来比较吓人。先来看一下进程,这个相对于线程来说还是稍微好理解一点。

进程,是程序运行的实体。

这句话的意思是,程序本身是存放在硬盘中的,当这个程序运行起来之后,就会产生相应的进程,而且这个进程是可以看到的。例如在 Windows 10 的任务管理器中,就可以看到很多进程:

Windows 10 的进程

什么是线程?

如果你编写过程序,特别是类似 Windows 批处理这样逻辑控制语句比较少的语言,就能明显感觉到:

当运行一个程序时,实际上整个运行过程是从头一直运行到尾。

例如下面这样一段批处理:

@echo off
set /p name=请输入您的姓名:
cls
echo 你好,%name%
pause

这段小程序就是自上而下执行的,执行完毕之后退出。

不管是批处理,还是 PHP、Node.js 等程序,都可以看到类似的执行过程。

实际上,这就是一个线程。

可以这样去理解:

线程是一个任务流,它被包含在进程之中。

用麦当劳的例子理解进程和线程

举一个比较容易理解的例子。

5 月 1 日这一天,麦当劳生意比较火爆,前台有 6 个窗口,其中有 4 个窗口在工作。

随着来吃饭的人越来越多,麦当劳不得不开放剩余的两个窗口。在这里,每一个窗口都可以理解为一个单独的工作单位,负责处理“卖食品”这样的任务。当系统需要处理更多请求的时候,开放更多窗口,就相当于增加更多的处理单位来满足需求。但是,由于是假期,即使 6 个窗口全部开放了,排队的客户还是很多。

那么,是不是就没有其他办法了?效率都是逼出来的。

经理发现,客户买完东西以后,需要在旁边等,等汉堡或者其他食品准备好了,再由另外一个人统一把食品送到对应的窗口。由于这个人需要同时给 6 个不同窗口送食品,所以效率比较低。这时候经理发话了:

食品准备好了,直接由窗口的售卖人员把食品交给正在等待的客户。

这样就可以节省一部分时间。在这个例子中,前台售卖人员原来只有一项工作:

售卖商品。

后来又增加了一项:

把已经准备好的食品交给客户。

也就是说,同一个工作单位中同时处理了两项任务。用这个例子来理解线程,就比较容易了:

一个进程可以包含一个或者多个线程,不同的线程可以处理不同的任务。

进程和线程简单总结

到这里,我们可以做一个比较简单的理解:

进程是程序运行起来之后的一个实体,线程则是进程中的具体任务流。

一个进程至少包含一个线程。如果一个进程中只有一个线程,那么就是一个比较简单的执行过程;如果一个进程中存在多个线程,那么就可以同时处理多个任务。下面来看一个 Python 的例子,让一个进程同时运行两个线程。

import time
import thread

def Ordering(interval):
cnt = 0
while cnt < 100:
print '好了,你订餐成功,订餐号码是:%d号 订餐时间是:%s 请在旁边耐心等待\n\n' % (
cnt,
time.ctime()
)
time.sleep(interval)
cnt += 1
thread.exit_thread()


def Notice(interval):
cnt = 0
while cnt < 100:
print '谁的号码是%d,您的餐好了,过来取一下\n' % (cnt)
time.sleep(interval)
cnt += 1
thread.exit_thread()


def work():
# Use thread.start_new_thread() to create 2 new threads
thread.start_new_thread(Ordering, (1,))
thread.start_new_thread(Notice, (5,))


if __name__ == '__main__':
work()

这里通过:

thread.start_new_thread()

创建了两个线程。

第一个线程负责 Ordering 模拟订餐。

第二个线程负责 Notice 模拟通知取餐。

这样,原本需要按照顺序执行的两个任务,就可以在同一个进程中分别运行。

从这个例子也可以比较直观地理解:

进程像一个大的工作容器,线程则是其中具体执行任务的工作流。

评论0

欢迎分享你的看法,也欢迎补充不同的实践经验。