Python 怎么并列执行?掌握并行编程技巧,提升效率,代码实战案例,小白也能轻松学会 Python 并行处理。

话说,Python 这种胶水语言,真是让人又爱又恨。爱它的简洁易懂,恨它的…速度!尤其是在处理大量数据的时候,那叫一个慢吞吞。但是,作为一名合格的 Python 玩家,怎么能容忍这种事情发生?必须想办法榨干它的每一滴性能啊!所以,今天我们就来聊聊 Python 怎么并列,也就是 Python 的并行编程。

先说结论,Python 里的并行,其实花样挺多的。最常用的可能就是多线程和多进程了。但问题也来了,Python 的全局解释器锁 (GIL) 可不是吃素的,它直接限制了多线程的并发执行,换句话说,多线程在 CPU 密集型任务面前,基本就是个摆设,只能在一个核心上跑。

那怎么办?凉拌?当然不!还有多进程呢!多进程可是真真正正的并行,每个进程都有自己独立的内存空间,不会受到 GIL 的限制。所以,对于 CPU 密集型任务,多进程才是王道!

但多进程也不是万能的。它的开销比多线程要大得多,创建和销毁进程都需要消耗大量的资源。而且,进程间的通信也比较麻烦,需要用到像 QueuePipe 这样的东西。

所以,选择哪个?这就要看你的具体情况了。如果是 I/O 密集型任务,比如网络请求、文件读写等等,多线程就足够了。因为大部分时间都花在等待 I/O 上,GIL 的限制影响不大。但如果是 CPU 密集型任务,比如图像处理、科学计算等等,那就必须用多进程了。

OK,理论讲完了,来点实际的。先来个多线程的例子。假设我们要下载一批图片,可以用 threading 模块来实现:

“`python
import threading
import requests

def download_image(url):
“””下载图片”””
try:
response = requests.get(url, stream=True)
response.raise_for_status() # 检查请求是否成功
filename = url.split(“/”)[-1]
with open(filename, “wb”) as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
print(f”Downloaded {filename}”)
except requests.exceptions.RequestException as e:
print(f”Error downloading {url}: {e}”)

if name == “main“:
image_urls = [
“https://www.easygifanimator.net/images/samples/video-to-gif-sample.gif”,
“https://upload.wikimedia.org/wikipedia/commons/2/2c/Rotating_earth_%28large%29.gif”,
“https://media.tenor.com/images/b9633dd20c4c44f189de4914765c6ae3/tenor.gif”
]
threads = []
for url in image_urls:
t = threading.Thread(target=download_image, args=(url,))
threads.append(t)
t.start()

for t in threads:
    t.join()  # 等待所有线程完成
print("All downloads completed.")

“`

这个例子很简单,就是创建多个线程,每个线程负责下载一张图片。t.join() 的作用是等待所有线程执行完毕,这样主线程才能继续往下执行。

再来个多进程的例子。假设我们要计算一个很大的数组的平方和,可以用 multiprocessing 模块来实现:

“`python
import multiprocessing
import numpy as np

def calculate_sum(arr):
“””计算数组的平方和”””
return np.sum(arr ** 2)

if name == “main“:
num_processes = multiprocessing.cpu_count() # 获取 CPU 核心数
arr = np.random.rand(1000000) # 创建一个很大的随机数组
chunk_size = len(arr) // num_processes # 将数组分成若干份
chunks = [arr[ichunk_size:(i+1)chunk_size] for i in range(num_processes)]

pool = multiprocessing.Pool(processes=num_processes)  # 创建进程池
results = pool.map(calculate_sum, chunks)  # 并行计算每个分块的平方和
pool.close()  # 关闭进程池
pool.join()  # 等待所有进程完成

total_sum = np.sum(results)  # 将所有分块的平方和加起来
print(f"Total sum: {total_sum}")

“`

这个例子稍微复杂一点。首先,我们获取 CPU 的核心数,然后将数组分成若干份,每一份交给一个进程去计算平方和。multiprocessing.Pool 创建一个进程池,可以方便地管理多个进程。pool.map 函数会将 calculate_sum 函数应用到每个分块上,并返回一个结果列表。最后,我们将所有分块的平方和加起来,得到最终的结果。

等等,还没完呢!除了多线程和多进程,还有其他一些并行编程的方法,比如:

  • asyncio: 基于事件循环的异步编程模型,适合 I/O 密集型任务。
  • concurrent.futures: 一个更高级的并发编程接口,可以方便地使用线程池和进程池。
  • Numba: 一个即时编译器,可以将 Python 代码编译成机器码,从而提高性能。
  • Cython: 一种 Python 的超集,可以编写 C 扩展,从而提高性能。

这些方法各有优缺点,需要根据具体情况选择。

说了这么多,其实 Python 的并行编程并没有想象中那么难。关键是要理解 GIL 的限制,选择合适的并发模型,并掌握一些常用的工具和技巧。只要掌握了这些,你就可以让你的 Python 代码飞起来了!而且,Python 的生态系统非常强大,有很多第三方库可以帮助你进行并行编程,比如 DaskRay 等等。 这些库可以让你更方便地处理大规模数据,并将其分布到多个机器上进行并行计算。简直不要太爽!

所以说,不要再抱怨 Python 慢了,赶紧学起来,让你的代码也跑得飞快! 毕竟,程序员的快乐,一半来自于解决 bug,另一半就来自于优化代码啊!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。