Python 并行处理
在如今快节奏的数字环境中,对于开发人员和数据科学家来说,高效地完成计算困难的任务至关重要。幸运的是,由于其适应性和广泛的生态系统,Python提供了强大的并行处理能力。通过将困难的问题分解为更小、更易处理的任务,并并行执行它们,我们可以获得显著的性能改进。
Python的并行处理功能使我们能够更快速、更有效地处理诸如网络爬虫、科学模拟和数据分析等活动,利用可用的计算资源。在这篇文章中,让我们通过Python并行处理的旅程。我们将探讨多种方法,包括多进程、异步编程和多线程,学习如何有效地使用它们来克服系统性能限制。加入我们,发现Python并行处理的全部潜力,实现更高的性能和生产力。
理解并行处理
将一个任务分解为更小的子任务,然后在多个处理器或核心上并行运行它们,这被称为并行处理。通过有效利用可用的计算资源,并行处理可以显著减少程序的总执行时间。Python提供了异步编程、多进程和多线程等多种并行处理方法。
Python中的多线程
使用多线程的方法,多个线程在同一个进程中并行运行,共享同一块内存。Python的线程模块可以很容易地实现多线程。然而,由于全局解释器锁(GIL)一次只允许一个线程执行Python字节码,所以多线程在CPU限制的操作中可能不会带来速度提升。然而,对于I/O限制的任务,多线程是很有用的,因为它允许线程在等待I/O操作完成时运行其他操作。
让我们看一个例子,我们使用多线程来下载许多网页:
示例
import threading import requests
def download_page(url):
response = requests.get(url)
print(f"Downloaded {url}")
urls = [
"https://example.com",
"https://google.com",
"https://openai.com"
]
threads = []
for url in
urls:
thread = threading.Thread(target=download_page,
args=(url,)) thread.start() threads.append(thread)
for thread in threads:
thread.join()
输出
Downloaded https://example.com
Downloaded https://google.com
Downloaded https://openai.com
多个下载可以同时进行,多亏了上面的代码片段,它在各自的线程中下载每个URL。join()函数确保主线程在继续之前等待每个线程完成。
Python中的多进程
与多线程相比,多进程通过使用几个带有自己内存空间的进程提供真正的并行处理。Python的multiprocessing模块提供了一个实现多进程的高级接口。多进程适用于CPU密集型活动,因为每个进程在独立的Python解释器中运行,避免了GIL多线程限制。
下面的代码中使用了多进程。一旦pool类生成了一个工作进程池,map()方法将任务分配给可用进程。结果列表是结果的集合。
看看下面的例子,我们使用多进程来计算一个列表中每个整数的平方:
示例
import multiprocessing
def square(number):
return number ** 2
numbers = [1, 2, 3, 4, 5]
with multiprocessing.Pool() as pool:
results = pool.map(square, numbers)
print(results)
输出
[1, 4, 9, 16, 25]
Python中的异步编程
通过利用非阻塞操作,异步编程可以高效执行I/O绑定的过程。由于asyncio包的存在,协程、事件循环和futures都可以用来创建Python中的异步代码。随着在线应用程序和API的流行,异步编程变得越来越重要。
下面的代码示例中,fetch_page()协程利用aiohttp异步获取网页。main()方法生成一个作业列表,并通过使用asyncio.gather()同时执行它们。要等待任务完成并接收结果,使用await关键字。
让我们来看一个使用asyncio和aiohttp异步获取多个网页的例子:
示例
import asyncio
import aiohttp
async def fetch_page(url): async with aiohttp.ClientSession() as session: async with session.get(url) as response:
return await response.text()
async def main():
urls = [
"https://example.com",
"https://google.com",
"https://openai.com"
]
tasks = [fetch_page(url) for url in urls] pages = await asyncio.gather(*tasks)
print(pages)
asyncio.run(main())
输出
['<!doctype html>\n<html>\n<head>\n <title>Example Domain</title>\n\n <meta
charset="utf-8" />\n <meta http-equiv="Content-type"content="text/html; charset=utf-8" />\n <meta name="viewport" content="width=device-width, initialscale=1" />\n <style type="text/css">\n body {\n background-color: #f0f0f2;\n margin: 0;\n padding: 0;\n font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;\n \n }\n div {\n width: 600px;\n margin: 5em auto;\n padding: 50px;\n background-color: #fff;\n border-radius: 1em;\n }\n a:link, a:visited {\n color: #38488f;\n text-decoration: none;\n }\n @media (maxwidth: 700px) {\n body {\n background-color: #fff;\n }\n div {\n width: auto;\n margin: 0 auto;\n border-radius: 0;\n padding: 1em;\n }\n }\n </style> \n</head>\n\n<body>\n<div>\n <h1>Example Domain</h1>\n <p>This domain is for use in illustrative examples in documents. You may use this\n domain in literature without prior coordination or asking for permission.</p>\n <p><a href="https://www.iana.org/domains/example">More information...</a></p>\n</div>\n</body>\n</html>', '<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="en"><head><meta content="Search the world's information, including webpages, images, videos and more. Google has many special features to help you find exactly what you're looking for." name="description"><meta content="noodp" name="robots"><meta content="text/html; charset=UTF-8" http-equiv="Content-Type"><meta content="/logos/doodles/2021/mom-
and-dad-6116550989716480.2-law.gif" itemprop="image"><link href="/logos/doodles/2021/mom-and-dad-6116550989716480.2-law.gif" rel="icon" type="image/gif"><title>Google</title><script nonce="sJwM0Ptp5a/whzxPtTD8Yw==">(function(){window.google={kEI:'cmKgYY37A7 K09QPhzKuACw',kEXPI:'1354557,1354612,1354620,1354954,1355090,1355493,13556
83,3700267,4029815,4031109,4032677,4036527,4038022,4043492,4045841,4048347,4
048490,4052469,4055589,4056520,4057177,4057696,4060329,4060798,4061854,4062 531,4064696,406 '
选择合适的方法
根据任务的具体内容,Python的并行处理技术有所不同。以下是一些指南,可以帮助您做出明智的决策:
对于I/O密集型活动,其中大部分执行时间都花在等待输入/输出操作上,多线程是合适的。它适用于下载文件、使用API和操作文件等任务。由于Python的全局解释器锁(GIL),多线程可能不会显著加快CPU密集型活动的速度。
另一方面,多进程非常适用于涉及大量计算的CPU密集型任务。它通过利用多个进程实现了真正的并行性,每个进程都有自己的内存空间,并且绕过了GIL的限制。然而,它会带来额外的开销,包括内存消耗和进程间通信。
对于涉及网络操作的I/O密集型活动,使用类似asyncio的库进行异步编程很有用。它利用非阻塞I/O操作,使作业可以继续进行,而不必等待每个操作完成。这种方法可以有效管理多个并发连接,适用于网络服务器开发、Web API交互和Web抓取。异步编程可以最大程度地减小I/O操作的等待时间,确保响应能力和可伸缩性。
结论
Python的并行处理能力为需要复杂计算的任务提供了增加效率的机会。无论您选择使用多线程、多进程还是异步编程,Python都提供了必要的工具和模块来有效地利用并发性。通过理解您的活动的性质并选择合适的技术,您可以最大限度地发挥并行处理的好处,缩短执行时间。因此,请放心地探索和利用Python的并行性,以实现更快、更高效的应用程序。