共计 2906 个字符,预计需要花费 8 分钟才能阅读完成。
欢送来到咱们的系列博客《Python 全景系列》!在这个系列中,咱们将率领你从 Python 的基础知识开始,一步步深刻到高级话题,帮忙你把握这门弱小而灵便的编程语法。无论你是编程老手,还是有肯定根底的开发者,这个系列都将提供你须要的常识和技能。
这是本系列的第五篇,咱们将深入探讨 Python 中的并发编程,特地关注多线程和多过程的利用。咱们将先从基本概念开始,而后通过具体举例探讨每一种机制,最初分享一些实战经验以及一种优雅的编程技巧。
第一局部:多线程介绍
线程是操作系统中最小的执行单元。在单个程序或过程内,能够并发运行多个线程,共享过程的资源,如内存和文件描述符。
1.1 Python 中的多线程
Python 反对多线程编程,并提供了 threading
模块作为反对。这个模块提供了 Thread
类,咱们能够通过创立其实例并向其传递函数来创立新线程。当然,你也能够通过继承 Thread
类并重写 run()
办法来创立自定义线程。上面是一个多线程编程的例子:
import threading
def print_numbers():
for i in range(10):
print(i)
def print_letters():
for letter in 'abcdefghij':
print(letter)
# 创立线程
t1 = threading.Thread(target=print_numbers)
t2 = threading.Thread(target=print_letters)
# 启动线程
t1.start()
t2.start()
# 期待线程完结
t1.join()
t2.join()
在下面的例子中,咱们定义了两个函数:一个打印数字,另一个打印字母。而后咱们创立了两个线程,每个线程的指标是执行这些函数。start()
办法用于启动线程,而 join()
办法用于期待线程实现。
1.2 多线程的理论利用
只管 Python 的多线程因为全局解释器锁(GIL)的存在,并不能实现真正的并行,然而它们在 I / O 密集型工作中依然很有用。GIL 是 CPython 解释器的一个互斥锁,保障在任何时刻只有一个线程在执行。这意味着在 CPU 密集型工作中,多线程可能不是最佳抉择,因为它们无奈充分利用多核 CPU。
然而,在 I / O 密集型工作中,多线程可能进步程序性能。例如,如果一个程序须要从多个源下载文件,那么应用多线程能够使得当一个线程期待网络响应时,其余线程能够持续下载其余文件。这样,程序能够在同一时间从多个源下载文件,大大提高了效率。
第二局部:多过程介绍
过程是操作系统中独立的执行实体,每个过程都有本人的内存空间、文件描述符等资源。与线程不同,过程之间的资源
并不共享,每个过程都有本人独立的资源。
2.1 Python 中的多过程
Python 通过 multiprocessing
模块提供了多过程反对。相似于多线程,咱们能够通过创立 Process
类的实例并向其传递函数来创立新过程。咱们也能够通过继承 Process
类并重写 run()
办法来创立自定义过程。
以下是一个简略的多过程编程的例子:
import multiprocessing
def print_numbers():
for i in range(10):
print(i)
def print_letters():
for letter in 'abcdefghij':
print(letter)
# 创立过程
p1 = multiprocessing.Process(target=print_numbers)
p2 = multiprocessing.Process(target=print_letters)
# 启动过程
p1.start()
p2.start()
# 期待过程完结
p1.join()
p2.join()
这个例子和后面的多线程例子相似,不同的是这里咱们创立的是两个过程,而不是线程。
2.2 多过程的理论利用
多过程能够实现真正的并行,使得 Python 程序能够利用多核 CPU。因而,对于 CPU 密集型工作,多过程通常比多线程更有劣势。另一方面,多过程的开销比多线程大,而且过程间的通信和同步也比线程间的更为简单。因而,对于 I / O 密集型工作,或者须要频繁通信的工作,多线程可能会是更好的抉择。
第三局部:优化并发编程的技巧
在 Python 中,concurrent.futures
模块为多线程和多过程编程提供了高级接口,能够让咱们更加简洁地编写代码。
这个模块提供了 ThreadPoolExecutor
和ProcessPoolExecutor
两个类,它们别离用于创立线程池和过程池。这两个类都实现了雷同的接口,你能够应用 submit()
办法提交工作,而后应用 as_completed()
函数期待工作实现。
上面是一个应用 concurrent.futures
模块的示例:
import concurrent.futures
def print_numbers():
for i in range(10):
print(i)
def print_letters():
for letter in 'abcdefghij':
print(letter)
# 应用线程池
with concurrent.futures.ThreadPoolExecutor() as executor:
future1 = executor.submit(print_numbers)
future2 = executor.submit(print_letters)
for future in concurrent.futures.as_completed([future1, future2]):
pass
# 应用过程池
with concurrent.futures.ProcessPoolExecutor() as executor:
future1 = executor.submit(print_numbers)
future2 = executor.submit(print_letters)
for future in concurrent.futures.as_completed([future1, future2]):
pass
在下面的例子中,咱们创立了线程池和过程池,而后向它们提交工作。能够看到,应用 concurrent.futures
模块,咱们的代码更加简洁,易读性和可维护性也有所提高。
总结
Python 的多线程和多过程都是十分弱小的工具,能够帮忙咱们编写出更高效的程序。然而,它们也各有优缺点,须要咱们依据具体的工作和需要来抉择。同时,Python 还提供了 concurrent.futures
模块,能够使咱们的并发编程变得更加简略和高效。
咱们心愿本文能帮忙你更好地了解和应用 Python 的多线程和多过程。如果你有任何疑难或者倡议,欢送在评论区留言。
【第一工夫取得 Python 全视角更新信息,请关注自己微信公众号: Python 全视角】
如有帮忙,请多关注
集体微信公众号:【Python 全视角】
TeahLead_KrisChang,10+ 年的互联网和人工智能从业教训,10 年 + 技术和业务团队治理教训,同济软件工程本科,复旦工程治理硕士,阿里云认证云服务资深架构师,上亿营收 AI 产品业务负责人。