python中3or5是什么意思,什么对应的是python2.7

  

  据雷锋网《AI技术评论》报道,本文是工程师Jim Anderson分享的《通过并发加速python程序》一文的第三部分。主要内容与CPU绑定程序加速相关。   

  

  在前两篇文章中,我们已经讨论了I/O绑定程序的相关概念和加速。这是本系列的最后一篇文章,讨论CPU程序加速。雷锋网AI技术评论编译如下:   

  

  如何加速 CPU 绑定程序   

  

  到目前为止,前面的例子已经处理了I/O绑定问题。现在,您将研究CPU绑定的问题。如你所见,I/O绑定的问题大多是等待外部操作(比如网络调用)完成。另一方面,CPU限制的问题只执行很少的I/O操作,它的整体执行时间取决于它处理所需数据的速度。   

  

  在我们的例子中,我们将使用一个有点愚蠢的函数来创建一些需要在CPU上长时间运行的东西。此函数计算从0到传入值的每个数字的平方和:   

  

  您将处理大量数据,因此需要一段时间。记住,这只是代码的占位符。它实际上做了一些有用的事情,需要大量的处理时间,比如计算公式的根或者对大型数据结构进行排序。   

  

  CPU 绑定的同步版本   

  

  现在让我们来看看这个例子的非并发版本:   

  

  导入时间   

  

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

  

  def find_sums(数字):   

  

  对于numbers:中的数字   

  

  cpu_bound(数字)   

  

  if __name__=='__main__':   

  

  numbers=5_000_000 x,x在范围(20)内   

  

  开始时间=时间.时间   

  

  find_sums(数字)   

  

  持续时间=时间.时间-开始时间   

  

  打印(f'Duration {duration}秒)   

  

  这段代码调用cpu_bound 20次,每次都使用不同的大数字。它在单个CPU上的单个进程中的单个线程上完成所有这些工作。执行顺序图如下:   

  

  与I/O绑定示例不同,CPU绑定示例通常运行得相当一致。这台机器大约需要7.8秒:   

  

  显然,我们可以做得更好。它全部运行在一个CPU上,没有并发性。让我们看看我们能做些什么来改善它。   

  

  线程和异步版本   

  

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

  

  如果你回答“一点也不”,那就有道理了。如果你回答“会减慢速度”,那就更是如此了。   

  

  原因如下:在上面的I/O绑定示例中,大部分时间都花在了等待慢速操作完成上。线程和异步可以通过允许重叠等待时间来加速,而不是按顺序执行。   

  

  但是,在CPU绑定的问题上,不需要等待。CPU将尽快启动以解决问题。在python中,线程和任务都在同一个进程的同一个CPU上运行。这意味着一个CPU不仅要做非并发代码的所有工作,还需要做线程或任务的额外工作。花了10多秒钟:   

  

  我已经编写了该代码的线程版本,并将其与其他示例代码一起放在Github repo中,以便您可以自己测试。   

  

  CPU 绑定的多处理版本   

  

  现在,你终于要接触和处理一些真正不同的东西了。与其他并发库不同,多处理被明确设计为在多个CPU之间共享工作负载。其执行时序图如下:   

  

  它的代码是这样的:   

  

  导入多重处理   

  

  导入时间   

  

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

  

  def find_sums(数字):   

  

  多重处理。作为池的池:   

  

  pool.map(cpu_bound,numbers)   

  

  if __name__=='__main__':   

  

  numbers=5_000_000 x,x在范围(20)内   

  

  开始时间=时间.时间   

find_sums(numbers)

  

duration = time.time - start_time

  

print(f"Duration {duration} seconds")

  

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

  

这正是你为 I/O 绑定的多处理代码所做的,但是这里你不需要担心会话对象。

  

如上所述,处理 multiprocessing.pool构造函数的可选参数值得注意。可以指定要在池中创建和管理的进程对象的数量。默认情况下,它将确定机器中有多少 CPU,并为每个 CPU 创建一个进程。虽然这对于我们的简单示例来说很有用,但你可能希望在生产环境它也能发挥作用。

  

另外,和我们在第一节中提到的线程一样,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 绑定程序加速

相关文章