外链论坛

 找回密码
 立即注册
搜索
查看: 64|回复: 4

怎么样利用并发性加速你的python程序(三):CPU 绑定程序加速

[复制链接]

2986

主题

3万

回帖

9956万

积分

论坛元老

Rank: 8Rank: 8

积分
99569168
发表于 2024-8-17 20:53:03 | 显示全部楼层 |阅读模式

雷锋网 AI 科技评论按,本文是工程师 Jim Anderson 分享的关于「经过并发性加快 python 程序的速度」的文案的第三部分,重点内容是 CPU 绑定程序加速关联

在前面两篇中,咱们已然讲过了关联的概念以及I/O 绑定程序的加速,这篇是这一系列文案的最后一篇,讲的是 CPU 程序加速。雷锋网 AI 科技评论编译整理如下:

怎样加速 CPU 绑定程序

日前为止,前面的例子都处理了一个 I/O 绑定问题。此刻,你将科研 CPU 绑定的问题。如你所见,I/O 绑定的问题大部分时间都在等待外边操作(如网络调用)完成。另一方面,CPU 限制的问题只执行很少的 I/O 操作,它的总体执行时间取决于它处理所需数据的速度。

咱们的示例中,咱们运用一个有点愚蠢的函数来创建有些必须在 CPU 上运行很长期的东西。此函数计算从 0 到传入值的每一个数字的平方和:

你将处理一大批数据,因此必须一段时间。记住,这只是代码的一个占位符,它实质上做了有些有用的事情,必须海量的处理时间,例如计算公式的根或对大型数据结构进行排序。

CPU 绑定的同步版本

此刻咱们看一下这个示例的非并发版本:

import time

def cpu_bound(number): return sum(i * i for i in range(number))

def find_sums(numbers):

for number in numbers:

cpu_bound(number)

if __name__ == "__main__":

numbers = [5_000_000 + x for x in range(20)]

start_time = time.time

find_sums(numbers)

duration = time.time - start_time

print(f"Duration {duration} seconds")

此代码调用 cpu_bound 20 次,每次运用区别的大数字。它在单个 CPU 上单个进程中的单个线程上完成所有这些工作。执行时序图如下:

与 I/O 绑定示例区别,CPU 绑定示例的运行时间一般相当一致。这台设备大约必须 7.8 秒:

显然咱们能够做得更好。这都是在并发性的单个 CPU 上运行的。让咱们瞧瞧咱们能做些什么来改善它。

线程和异步版本

你认为运用线程或异步重写此代码会加快速度吗?

倘若你回答「一点不」,这是有道理的。倘若你回答,「它会减慢速度,」那就更对啦。

原由如下:在上面的 I/O 绑定示例中,大部分时间都花在等待缓慢的操作完成上。线程和异步经过准许你重叠等待的时间而不是按次序执行,这能加快速度。

然则,在 CPU 绑定的问题上,不必须等待。CPU 会尽可能快速地起步处理问题。在 python 中,线程和任务都在同一进程中的同一个 CPU 上运行。这寓意着一个 CPU 不仅做了非并发代码的所有工作,还必须做线程或任务的额外工作。它花费的时间超过 10 秒:

已然编写了这个代码的线程版本,并将它与其他示例代码放在 Github repo 中,这般你就能够自己测试它了。

CPU 绑定的多处理版本

此刻,你最终要接触多处理真正与众区别地区啦。与其他并发库区别,多处理被显式设计为跨多个 CPU 一起承担工作负载。它的执行时序图如下所示:

它的代码是这般的:

import multiprocessing

import time

def cpu_bound(number): return sum(i * i for i in range(number))

def find_sums(numbers):

with multiprocessing.Pool as pool:

pool.map(cpu_bound, numbers)

if __name__ == "__main__":

numbers = [5_000_000 + x for x in range(20)]

start_time = time.time

find_sums(numbers)

duration = time.time - start_time

print(f"Duration {duration} seconds")

这些代码和非并发版本相比几乎要更改的。你必要导入多处理,而后把数字循环改为创建多处理.pool 对象,并运用其.map办法在工作进程空闲时将单个数字发送给它们。

这正是你为 I/O 绑定的多处理代码所做的,然则这儿你不必须担心会话对象。

如上所述,处理 multiprocessing.pool构造函数的可选参数值得重视能够指定要在池中创建和管理的进程对象的数量。默认状况下,它将确定机器中有多少 CPU,并为每一个 CPU 创建一个进程。虽然这针对咱们的简单示例来讲特别有用,但你可能期盼在生产环境它能发挥功效

另一,和咱们第1节中说到的线程同样,multiprocessing.Pool 的代码是创立在 Queue 和 Semaphore 上的,这针对运用其他语言执行多线程和多处理代码的人来讲是很熟练的。

为何多处理版本很重要

这个例子的多处理版本非常好,由于它相对容易设置,并且只必须很少的额外代码。它还充分利用了计算机中的 CPU 资源。在我的设备上,运行它只必须 2.5 秒:

这比咱们看到的其他办法要好得多。

多处理版本的问题

运用多处理有有些缺点。在这个简单的例子中,这些缺点并透出来,然则将你的问题分解开来,以便每一个处理器都能独立工作有时是很困难的。另外,许多处理方法必须在流程之间进行更加多的通信,这相比非并发程序来讲繁杂得多。雷锋网

何时运用并发性

首要,你应该判断是不是应该运用并发模块。虽然这儿的示例使每一个库看起来非常简单,但并发性总是伴同着额外的繁杂性,并且常常会导致难以找到的错误。

保持添加并发性,直到显现已知的性能问题,而后确定必须哪种类型的并发性。正如 DonaldKnuth 所说,「过早的优化是编程中所有劫难最少大部分劫难)的根源(Premature optimization is the root of all evil (or at least most of it) in programming)」。

一旦你决定优化你的程序,弄清楚你的程序是 CPU 绑定的还是 I/O 绑定的,这便是下一步要做的事情。记住,I/O 绑定的程序是哪些花费大部分时间等待事情完成的程序,而 CPU 绑定的程序则尽可能快地处理数据。

正如你所看到的,CPU 绑定的问题实质仅有运用多处理才可处理。线程和异步基本帮忙处理这类问题。

针对 I/O 绑定的问题,python 社区中有一个通用的经验规则:「能够运用异步,必要运用线程。」异步能够为这种类型的程序供给最佳的速度,但有时必须某些关键库来利用它。记住,任何不放弃对事件循环掌控的任务都将阻塞所有其他任务。

CPU 绑定加速的内容就到此为止啦,认识更加多拜访原文!

前面的部分请查看:

怎样利用并发性加速你的python程序(一):关联概念

怎样利用并发性加速你的python程序(二):I/O 绑定程序加速





上一篇:看不见摸不到的东西,诗该怎么写?
下一篇:怎么样运用Python脚本分析CPU的运用状况?
回复

使用道具 举报

3045

主题

3万

回帖

9910万

积分

论坛元老

Rank: 8Rank: 8

积分
99109052
发表于 2024-10-20 04:43:19 | 显示全部楼层
感谢楼主分享,祝愿外链论坛越办越好!
回复

使用道具 举报

3090

主题

3万

回帖

9909万

积分

论坛元老

Rank: 8Rank: 8

积分
99098764
发表于 2024-11-1 21:33:58 | 显示全部楼层
你的见解独到,让我受益匪浅,非常感谢。
回复

使用道具 举报

3045

主题

3万

回帖

9910万

积分

论坛元老

Rank: 8Rank: 8

积分
99109052
发表于 2024-11-7 03:45:58 | 显示全部楼层
外贸论坛是我们的,责任是我们的,荣誉是我们的,成就是我们的,辉煌是我们的。
回复

使用道具 举报

3062

主题

3万

回帖

9913万

积分

论坛元老

Rank: 8Rank: 8

积分
99139046
发表于 2024-11-14 07:57:47 | 显示全部楼层
我深感你的理解与共鸣,愿对话长流。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

站点统计|Archiver|手机版|小黑屋|外链论坛 ( 非经营性网站 )|网站地图

GMT+8, 2024-11-23 06:54 , Processed in 0.119573 second(s), 22 queries .

Powered by Discuz! X3.4

Copyright © 2001-2023, Tencent Cloud.