多线程适用于IO密集型任务,因GIL在IO等待时释放,可实现高效并发;多进程则通过独立解释器绕过GIL,适合CPU密集型任务实现真正并行,但存在内存开销大、IPC复杂等问题。

在Python中,实现多线程主要依赖于内置的
threading
multiprocessing
谈到Python的并发编程,这本身就是一个充满了权衡与抉择的领域。我个人在处理一些高并发或计算密集型任务时,常常在这两者之间摇摆。但最终的决策,往往是基于对任务特性和Python自身机制的深刻理解。
多线程:为IO密集型任务而生
当我们使用
threading
立即学习“Python免费学习笔记(深入)”;
一个基本的多线程例子是这样的:
import threading
import time
def task(name):
print(f"线程 {name}: 启动")
time.sleep(2) # 模拟IO操作,比如网络请求或文件读写
print(f"线程 {name}: 完成")
if __name__ == "__main__":
threads = []
for i in range(3):
thread = threading.Thread(target=task, args=(f"T-{i}",))
threads.append(thread)
thread.start() # 启动线程
for thread in threads:
thread.join() # 等待所有线程完成
print("所有线程任务完成。")这段代码中,
time.sleep(2)
多进程:突破GIL,实现CPU密集型任务的并行
multiprocessing
下面是一个多进程的简单示例:
import multiprocessing
import time
def cpu_intensive_task(name):
print(f"进程 {name}: 启动")
result = 0
for _ in range(1_000_000): # 模拟大量计算
result += 1
print(f"进程 {name}: 完成,结果为 {result}")
return result
if __name__ == "__main__":
processes = []
for i in range(3):
process = multiprocessing.Process(target=cpu_intensive_task, args=(f"P-{i}",))
processes.append(process)
process.start() # 启动进程
for process in processes:
process.join() # 等待所有进程完成
print("所有进程任务完成。")在这个例子里,
cpu_intensive_task
Queue
Pipe
Manager
这是一个我经常被问到的问题,也是很多Python初学者会感到困惑的地方。坦白说,对于纯Python代码,答案是“不能真正并行”。这里,我们必须提到Python的“全球解释器锁”(Global Interpreter Lock),简称GIL。
GIL是一个互斥锁,它保护着Python解释器,确保在任何时刻,只有一个线程能够执行Python字节码。这意味着,即使你的机器有16个CPU核心,当你在Python中运行多线程时,也只有一个核心在执行Python代码。其他的Python线程,即便它们“准备就绪”,也必须等待GIL被释放才能轮到它们。这听起来可能有点反直觉,甚至让人觉得Python的多线程是“假的”。
然而,这并不意味着多线程毫无用处。GIL在某些情况下会被释放,最典型的就是当线程执行I/O操作时。比如,当一个线程发起一个网络请求,或者在等待硬盘读写完成时,它会主动释放GIL。这样一来,其他Python线程就可以趁机获取GIL并执行它们的任务。这就是为什么多线程在处理IO密集型任务时表现出色:它利用了等待I/O的时间片,让多个任务看起来像是同时进行的。
想象一下,你有一组工人(线程),他们都需要使用一台打印机(Python解释器)。GIL就像是打印机旁的一个保安,一次只允许一个工人使用打印机。但是,如果一个工人去接电话(IO操作),保安就会让出打印机给下一个工人。所以,虽然没有两个工人能同时打印,但他们可以高效地轮流使用打印机,尤其是在打电话的工人等待时间很长的情况下。
所以,如果你正在编写一个需要频繁进行网络通信、数据库查询或文件操作的程序,多线程仍然是你的好朋友。它能有效提升程序的并发能力,而你无需为此付出进程创建和管理的高昂代价。但如果你的任务是密集的数学计算、图像处理或数据分析,那你就得考虑多进程了。
在我看来,选择多进程通常是当你发现你的Python程序在单核上跑得飞快,但在多核上却无法充分利用所有核心时。这几乎是GIL在CPU密集型任务上施加的直接影响。
优势:
多进程最大的优势在于它能彻底绕开GIL。每个进程都有自己独立的内存空间和Python解释器实例。这意味着,当你启动多个进程时,它们可以真正地在多个CPU核心上并行执行Python字节码,实现真·并行。对于那些需要大量计算、数据处理、科学模拟等CPU密集型任务,多进程是提升性能的“银弹”。例如,我曾处理过一个需要对大量图像进行复杂算法处理的项目,一开始用多线程,性能提升微乎其微,后来切换到多进程,直接让处理时间缩短了数倍。
资源开销与挑战:
当然,这种并行能力并非没有代价。
Queue
Pipe
Value
Array
Manager
尽管有这些开销,但对于那些核心瓶颈在于CPU计算的任务,多进程的优势是压倒性的。
multiprocessing.Pool
在我的实践中,无论是多线程还是多进程,都会遇到一些令人头疼的问题。这些问题往往隐藏得很深,一旦出现,调试起来颇费周折。
常见陷阱:
+1
+2
threading.Lock
multiprocessing.Lock
Semaphore
Condition
Queue
Pipe
acquire(timeout=...)
multiprocessing.Value
Array
Manager
thread.daemon = True
process.daemon = True
join()
with
finally
调试技巧:
并发编程的调试是出了名的困难,因为错误往往是非确定性的,难以重现。
logging
pdb
pdb.set_trace()
Queue
Queue
总之,并发编程是一个充满挑战但又极其强大的领域。深入理解其底层机制,并掌握这些调试技巧,能让你在面对复杂问题时更加从容。
以上就是python怎么实现多线程或多进程_python多线程与多进程编程入门的详细内容,更多请关注php中文网其它相关文章!
python怎么学习?python怎么入门?python在哪学?python怎么学才快?不用担心,这里为大家提供了python速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号