返回介绍

11.2 多进程与多线程

发布于 2024-01-23 21:41:46 字数 1810 浏览 0 评论 0 收藏 0

正如前面解释的,因为GIL的问题,多线程并非好的可扩展性方案。更好的方案是Python中提供的multiprocessing包。它提供了类似multithreading模块中的接口,区别在于它会启动一个新的进程(通过fork(2))而不是一个新的系统线程。

下面是一个简单的例子,计算100万个随机整数的和8次,同时将其分散到8个线程中。

使用多线程的worker

import random
import threading

results = []

def compute():
  results.append(sum(
    [random.randint(1, 100) for i in range(1000000)]))

workers = [threading.Thread(target=compute) for x in range(8)]
for worker in workers:
  worker.start()
for worker in workers:
  worker.join()
print("Results: %s" % results)

程序的运行结果如示例11.1所示。

示例 11.1 time python worker.py的运行结果

$ time python worker.py
Results: [50517927, 50496846, 50494093, 50503078, 50512047, 50482863, 50543387, 50511493]
python worker.py 13.04s user 2.11s system 129% cpu 11.662 total

这个程序运行在四核的CPU上,这意味着Python最多可以利用400%的CPU能力。但显然它做不到,即使并行运行8个进程,它仍然卡在了129%,这只是硬件能力的32%。

现在,我们使用multiprocessing重写一下如示例11.2所示。对于这种简单的例子来说,实现是相当直接的。

示例 11.2  使用multiprocessing的 worker

import multiprocessing
import random

def compute(n):
  return sum(
    [random.randint(1, 100) for i in range(1000000)])

# Start 8 workers
pool = multiprocessing.Pool(8)
print("Results: %s" % pool.map(compute, range(8)))

在同样的条件下运行这个程序,结果如示例11.3所示。

示例 11.3 time python worker.py的运行结果

$ time python workermp.py
Results: [50495989, 50566997, 50474532, 50531418, 50522470, 50488087, 50498016, 50537899]
python workermp.py 16.53s user 0.12s system 363% cpu 4.581 total

执行时间减少到60%,这次程序可以消耗363%的CPU能力,超过CPU能力的90%。

此外,multiprocessing模块不仅可以有效地将负载分散到多个本地处理器上,而且可以通过它的multiprocessing.managers对象在网络中分散负载。它还提供了双向传输,以使进程间可以彼此交换信息。

每次考虑在一定的时间内并行处理一些工作时,最好是依靠多进程创建(fork)多个作业,以便能够在多个CPU核之间分散负载。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文