Python:异步线程有什么优势?

时间:2017-12-29 09:51:07

标签: python multithreading async-await

我很难尝试了解异步功能在python中的工作原理和原因,我仍然不确定我是否正确理解了所有内容(特别是'为什么'部分)。如果我错了,请纠正我。

异步方法和线程的目的是使同时处理多个任务成为可能。

线程方法看起来简单直观。如果python程序同时处理多个任务,我们每个任务都有一个线程(可能有子线程),每个线程的堆栈反映了当前处理相应任务的阶段。一切都很简单,有一些易于使用的机制来启动新线程并等待它的结果。

据我所知,这种方法的唯一问题是线程很昂贵。

另一种方法是使用async协同程序。我可以通过这种方法看到一些不便之处。我只会说出几个人的名字。我们现在有两种方法:常用方法和async方法。 90%的时间唯一的区别是您需要记住此方法是async并且在调用此方法时不要忘记使用await关键字。是的,您无法从正常方法调用async方法。并且程序周围的所有async - await语法垃圾只是表明此方法能够控制消息循环。

线程方法没有任何这些不便之处。但是async - await方法允许处理比线程方法更多的并发任务。怎么可能?

对于每个并发任务,我们仍然有一个调用堆栈,现在它只是一个协程调用堆栈。我不太确定,但看起来这是关键的区别:通常的堆栈是操作系统堆栈,它们很昂贵,协程栈只是一个python结构,它们便宜得多。这是我的理解是正确的吗?

如果这是正确的,那么从操作系统线程/调用堆栈中解除python线程/调用堆栈以使python线程更便宜会不会更好?

很抱歉,如果这个问题很愚蠢。我确信选择async - await方法有一些原因。只是想了解这些原因。

更新

对于那些不认为这个问题不好而且过于宽泛的人。

这是一篇文章Unyielding - 首先解释为什么线程不好并且广告async接近。主要论点:线程是邪恶的,很难推断出可以同时从任意数量的线程执行的例程。

感谢Nathaniel J. Smith(python Trio图书馆的作者)建议这个链接。

顺便说一句,文章中的论据对我来说并不令人信服,但仍然有用。

2 个答案:

答案 0 :(得分:1)

This article回答了您的问题。

TL; DR?

由于GIL(全局解释器锁定),Python中的线程效率低下,这意味着多个线程无法像多处理器系统上那样并行运行。另外,你必须依靠解释器在线程之间切换,这会增加低效率。

asyc / asyncio允许在单个线程内进行并发。作为开发人员,这使您可以对任务切换进行更细粒度的控制,并且可以为并发I / O绑定任务提供比Python线程更好的性能。

你不提及的第三种方法是multiprocessing。这种方法使用并发进程,并允许程序充分利用具有多个内核的硬件。

答案 1 :(得分:1)

Asyncio是一个完全不同的世界,而AFAIK它是node.js的python的答案,它从一开始就做了这件事。例如。关于asyncio的这个official python doc

  

异步编程与传统的“顺序”编程不同

所以你需要决定是否要跳进那个兔子洞并学习这个术语。如果您遇到网络或磁盘相关的繁重任务,这可能才有意义。如果你是那么,例如this article声称python 3的asyncio可能比node.js快,并且接近Go的性能。

那说:我还没有使用过asyncio,所以我不能真正对此做出反应,但我可以对你问题中的几句话发表评论:

  

所有这些异步 - 等待程序周围的语法垃圾只是表明这个方法能够控制消息循环

据我所知,你有asyncio的初始设置,但是所有调用的语法都比使用start()join()所需的线程做同样的事情要少。可能还要检查is_alive(),并获取首先设置共享对象所需的返回值。所以:不,asyncio只是看起来不同,但最终程序看起来很可能看起来比使用线程更清晰。

  

据我所知,这种方法唯一的问题是线程昂贵

不是真的。开始一个新线程是非常便宜的,并且AFAIK与在C或Java中启动“本机线程”的成本相同

  

看起来这是关键区别:通常的堆栈是操作系统堆栈,它们很昂贵,协程栈只是一个python结构,它们便宜得多。这是我的理解是正确的吗?

不是真的。没有什么比创建操作系统级线程更好,它们很便宜。 asyncio更擅长的是你需要更少的线程切换。因此,如果你有许多并发线程在等待网络或磁盘,那么asyncio可能会加快速度。