在本教程中,您将学习如何使用 Python 的内置线程模块探索 Python 的多线程功能。
了解多线程在 Python 中的工作原理,从进程和线程的基础知识开始,了解并发和并行的概念。接下来,了解如何使用内置threading
模块在 Python 中启动和运行一个或多个线程。
让我们开始吧。
进程和线程:区别
流程是怎样的?
进程是需要运行的程序的实例。
它可以是任何东西,从 Python 脚本和 Web 浏览器(如 Chrome)到视频会议应用程序。您可以通过在计算机上启动任务管理器并导航到性能–> CPU来查看当前正在 CPU 内核上运行的进程和线程。

了解进程和线程
在内部,进程有专用的内存来存储与进程相对应的代码和数据。
一个进程由一个或多个线程组成。线程是操作系统可以执行的最小指令序列,代表执行流程。
每个线程都有自己的堆栈和寄存器,但没有专用的内存。与该进程关联的所有线程都可以访问该数据。因此,数据和内存由进程的所有线程共享。

具有 N 个核心的 CPU 可以同时并行运行 N 个进程。但是,同一个进程的两个线程不能同时运行,但是可以并发运行。以下各节解释并发和并行的概念。
根据到目前为止所学的知识,我们来总结一下进程和线程之间的区别。
特征 | 过程 | 线 |
记忆 | 专用内存 | 共享内存 |
执行模式 | 并行的,同时的 | 同时;但不是并行 |
执行处理人 | 操作系统 | CPython解释器 |
Python 中的多线程
在Python中, 全局解释器锁(GIL)确保任何时候只有一个线程可以获得锁并执行。所有线程都必须获得该锁才能执行。这允许任何时候只运行一个线程,避免同时多线程。
例如,考虑同一进程中的两个线程t1
和t2
。线程共享相同的数据,因此当t1
读取特定值k
时, t2
可能会更改相同的值k
。这可能会导致僵局和不良结果。但是,任何时候只有一个线程可以获得锁并执行。因此,GIL也保证了线程安全。
那么我们如何在Python中实现多线程呢?为了理解这一点,我们先讨论一下并发和并行的概念。
并发和并行:概述
考虑具有多个核心的 CPU。在下图中,CPU 有四个核心。这意味着可以随时并行执行四个不同的操作。
如果有四个进程,则每个进程可以在四个核心上独立且同时运行。假设每个进程有两个线程。

为了了解线程如何工作,让我们从多核处理器架构切换到单核处理器架构。如前所述,在给定的执行实例中只能有一个线程处于活动状态。然而,处理器核心可以切换线程。

例如,I/O 绑定线程经常等待 I/O 操作,例如读取用户输入、读取数据库和文件操作。在此等待时间内,I/O 绑定线程会释放其锁以允许其他线程运行。等待时间也可以是一个简单的操作,比如休眠n
秒。
摘要:在等待操作期间,线程释放锁,从而允许处理器核心切换到另一个线程。一旦等待期结束,前一个线程就会恢复执行。处理器核心同时在线程之间切换的过程有利于多线程处理。 ✅
如果您想在应用程序中实现进程级并行性,请考虑使用多处理。
Python 线程模块:第一步
Python 附带了一个threading
模块,您可以将其导入到 Python 脚本中。
import threading
要在 Python 中创建线程对象,可以使用Thread
构造函数threading.Thread(...)
。对于大多数线程实现来说,这是足够通用的语法。
threading.Thread(target=...,args=...)
这里,
-
target
是一个关键字参数,指示 Python 可调用对象。 -
args
是目标接收的参数元组。
运行本教程中的代码示例需要 Python 3.x。 下载代码并按照步骤操作。
在 Python 中定义和运行线程
让我们定义将执行目标函数的线程。
目标函数是some_func
。
import threading
import time
def some_func():
print("Running some_func...")
time.sleep(2)
print("Finished running some_func.")
thread1 = threading.Thread(target=some_func)
thread1.start()
print(threading.active_count())
我们来分析一下上面的代码片段做了什么。
- 导入
threading
和time
模块。 - 函数
some_func
有一个解释性的print()
语句,并包含 2 秒的睡眠操作。time.sleep(n)
使函数休眠n
秒。 - 接下来,使用目标
some_func
定义线程thread_1
。threading.Thread(target=...)
创建一个线程对象。 - 注意:指定函数的名称,而不是函数调用。使用
some_func
而不是some_func()
。 - 创建线程对象并不启动线程。当您调用线程对象的
start()
方法时执行。 - 要获取活动线程数,请使用
active_count()
函数。
Python 脚本在主线程上运行,并创建另一个运行函数some_func
的线程 ( thread1
)。因此,正如您在输出中看到的,活动线程数为 2。
# Output
Running some_func...
2
Finished running some_func.
如果仔细观察输出,您会发现第一个 print 语句是在thread1
启动时执行的。然而,在睡眠操作期间,处理器不会等待thread1
完成执行,而是切换到主线程并打印活动线程的数量。

等待线程完成执行
如果想让thread1
结束执行,可以在启动线程后调用join()
方法。这样做会等到thread1
完成执行而不会切换到主线程。
import threading
import time
def some_func():
print("Running some_func...")
time.sleep(2)
print("Finished running some_func.")
thread1 = threading.Thread(target=some_func)
thread1.start()
thread1.join()
print(threading.active_count())
在这里, thread1
在打印活动线程数之前完成了执行。所以只有主线程在运行。即活动线程数为1。 ✅
# Output
Running some_func...
Finished running some_func.
1
如何在Python中运行多线程
接下来,让我们创建两个执行两个不同功能的线程。
这里, count_down
是一个函数,它接受一个数字作为参数,并从该数字倒数到 0。
def count_down(n):
for i in range(n,-1,-1):
print(i)
定义count_up
。这是另一个从零计数到指定数字的 Python 函数。
def count_up(n):
for i in range(n+1):
print(i)
📑
range()
函数与range(start, stop, step)
语法一起使用时,默认stop
终点站。– 要从特定数字倒数到零,请使用负
step
值 -1 并将stop
值设置为 -1 以包含零。– 同样,要计数到
n
,stop
值必须设置为n + 1
。start
和step
的默认值分别是0和1,因此可以使用range(n + 1)
来获取从0到n的序列。
接下来,定义两个线程thread1
和thread2
分别执行count_down
和count_up
函数。向这两个函数添加print
语句和sleep
操作。
请注意,创建线程对象时,必须在args
参数中将目标函数参数指定为元组。这两个函数( count_down
和count_up
)都采用一个参数,因此您必须在值后面显式插入一个逗号。这会将后续元素推断为None
,因此参数仍作为元组传递。
import threading
import time
def count_down(n):
for i in range(n,-1,-1):
print("Running thread1....")
print(i)
time.sleep(1)
def count_up(n):
for i in range(n+1):
print("Running thread2...")
print(i)
time.sleep(1)
thread1 = threading.Thread(target=count_down,args=(10,))
thread2 = threading.Thread(target=count_up,args=(5,))
thread1.start()
thread2.start()
在输出中,它看起来像这样:
- 函数
count_up
在thread2
中执行,从0开始计数到5。 -
count_down
函数在thread1
上运行并从 10 倒数到 0。
# Output
Running thread1....
10
Running thread2...
0
Running thread1....
9
Running thread2...
1
Running thread1....
8
Running thread2...
2
Running thread1....
7
Running thread2...
3
Running thread1....
6
Running thread2...
4
Running thread1....
5
Running thread2...
5
Running thread1....
4
Running thread1....
3
Running thread1....
2
Running thread1....
1
Running thread1....
0
可以看到thread1
和thread2
交替运行,因为它们都需要等待操作(睡眠)。当count_up
函数计数到 5 时, thread2
不再处于活动状态。因此,您将仅获得与thread1
相对应的输出。
概括
在本教程中,您学习了如何使用 Python 的内置线程模块实现多线程。要点总结如下。
- 您可以使用Thread构造函数创建线程对象。 threading.Thread(target=<callable>,args=(<tuple of args>))创建一个线程,该线程使用args指定的参数运行目标可调用对象。
- Python程序在主线程上运行,因此您创建的线程对象是附加线程。调用active_count()函数会返回任何实例中的活动线程数。
- 您可以使用线程对象的start()方法启动线程,并使用join()方法等待它执行完毕。
您可以通过调整等待时间或尝试不同的 I/O 操作来编写其他示例。请务必在未来的 Python 项目中实现多线程。祝你编码愉快!🎉