我从未使用过async-await
语法,但是在等待将来的响应时,我确实经常需要发出HTTP / S请求并解析响应。为了完成此任务,我目前使用ThreadPoolExecutor类,该类无论如何都异步执行调用。有效地,我可以达到(我相信)使用更多行代码来使用async-await
所获得的相同结果。
假设当前的实现异步运行,我想知道async-await
的实现与我原来使用线程和队列来管理工作程序的实现有何不同?它还使用信号量来限制工作人员。
该实现是在以下条件下设计的:
实现的基本流程如下:
while
检查ListeningQueue 因为我需要限制使用信号量的活动线程的数量,并且如果要使用async-await
进行尝试,则必须在主线程或async def
中设计一些逻辑如果达到限制,则阻止发送请求。除了这种限制,我看不出在哪里使用async-await
会更有用。是否通过消除线程来降低开销和竞争条件的机会?那是主要好处吗?如果是这样,即使使用ThreadPoolExecutor进行异步调用,也使用线程池,从而使async-await
成为更好的选择吗?
答案 0 :(得分:2)
假设当前的实现异步运行,我想知道async-await实现与我原来使用线程和队列管理工作程序的实现有何不同
使用asyncio和async-await来实现非常相似的逻辑并不难,后者具有自己的semaphore版本,其使用方式几乎相同。有关使用固定数量的任务或使用信号量限制并行请求数量的示例,请参见this question的答案。
关于asyncio与使用线程的等效代码相比的优势,有几个:
所有内容均在单个线程中运行,无论活动连接的数量如何。您的程序可以扩展到大量并发任务,而不会因为线程数量不合理而淹没了操作系统,也不必等待线程池中的空闲插槽开始下载。
正如您所指出的那样,单线程执行不太容易出现竞争状况,因为可以在发生任务切换的点上用await
清楚地标记,并且它们之间的所有内容实际上都是原子的。这种优点在小型线程程序中不太明显,在小型线程程序中,执行程序只是以即发即发的方式将任务交给线程,但是随着逻辑变得越来越复杂,线程开始共享更多状态(例如,由于缓存或某些原因)同步逻辑),这变得更加明显。
异步/等待使您可以轻松地为监视,日志记录和清除之类的操作创建其他独立任务。使用线程时,那些线程不适合执行程序模型,并且需要其他线程,并且总是带有暗示线程被滥用的设计气味。使用asyncio,每个任务都可以像在自己的线程中运行一样,并使用await
等待某些事情发生(并控制其他事务)-例如一个基于计时器的监视任务将由一个等待asyncio.sleep()
的循环组成,但逻辑可能会非常复杂。尽管代码看起来是顺序的,但是每个任务都是轻量级的,并且对操作系统的权重不比分配的小对象大。
async / await支持可靠的取消,线程从未执行过并且可能永远不会执行。这通常被忽略,但是在异步中,完全有可能cancel运行中的任务,这会导致它从await
唤醒,但会终止它。取消使使用超时,任务组和其他模式变得简单明了,这些超时,任务组和其他模式在使用线程时是不可能的或繁琐的工作。
另一方面,异步/等待的缺点是所有代码都必须异步。除其他外,这意味着您不能使用诸如请求之类的库,而必须切换到aiohttp之类的支持异步的替代方案。