多线程编程 - 线程和进程
1. 进程
计算机程序只是存储在磁盘上的可执行二进制 (或其他类型) 文件。只有把它们加载到内存中并被操作系统调用,才拥有其生命期。进程 (有时称为重量级进程) 则是一个执行中的程序。每个进程都拥有自己的地址空间、内存、数据栈以及其他用于跟踪执行的辅助数据。操作系统管理其上所有进程的执行,并为这些进程合理地分配时间。进程也可以通过派生 (fork 或 spawn) 新的进程来执行其他任务,不过因为每个新进程也都拥有自己的内存和数据栈等,所以只能采用进程间通信 (IPC) 的方式共享信息。
fork [fɔːk]:n. 叉,餐叉,耙 vt. 叉起,使成叉状 vi. 分叉,分歧
spawn [spɔːn]:v. 产卵,酿成,造成,大量生产,生 (孩子,多指不想要的孩子)n. 卵,菌丝,产物
2. 线程
线程 (有时候称为轻量级进程) 与进程类似,不过它们是在同一个进程下执行的,并共享相同的上下文。可以将它们认为是在一个主进程或主线程中并行运行的一些迷你进程。
线程包括开始、执行顺序和结束三部分。它有一个指令指针,用于记录当前运行的上下文。当其他线程运行时,它可以被抢占 (中断) 和临时挂起 (也称为睡眠) — 这种做法叫做让步 (yielding)。
一个进程中的各个线程与主线程共享同一片数据空间,因此相比于独立的进程而言,线程间的信息共享和通信更加容易。线程一般是以并发方式执行的,正是由于这种并行和数据共享机制,使得多任务间的协作成为可能。在单核 CPU 系统中,真正的并发是不可能的。线程的执行实际上是这样规划的:每个线程运行一小会儿,然后让步给其他线程 (再次排队等待更多的 CPU 时间)。在整个进程的执行过程中,每个线程执行它自己特定的任务,在必要时和其他线程进行结果通信。
当然,这种共享并不是没有风险的。如果两个或多个线程访问同一片数据,由于数据访问顺序不同,可能导致结果不一致。这种情况通常称为竞态条件 (race condition)。幸运的是,大多数线程库都有一些同步原语,以允许线程管理器控制执行和访问。
另一个需要注意的问题是,线程无法给予公平的执行时间。这是因为一些函数会在完成前保持阻塞状态,如果没有专门为多线程情况进行修改,会导致 CPU 的时间分配向这些贪婪的函数倾斜。
References
Python 核心编程 (第 3 版)