我一直很难理解Python中异步功能的实现和原因,特别是“为什么”部分。如果我错了,请纠正我。
异步方法和线程的目的都是使多个任务可以同时处理。
线程方法看起来简单而直观。如果Python程序要并发处理多个任务,我们为每个任务分配一个线程(可以有子线程),每个线程的堆栈反映对应任务的当前处理阶段。一切都很简单,有易于使用的机制来启动新的线程并等待其结果。
据我所知,这种方法唯一的问题就是线程开销很大。
另一种方法是使用async
协程。我能看到几个不便之处。我只列举其中的两个。现在我们有两种类型的方法:普通方法和async
方法。90%的时间唯一的区别是你需要记住这个方法是async
的,并且在调用此方法时不要忘记使用await
关键字。是的,你不能从普通方法中调用async
方法。而所有这些async
-await
的语法垃圾只是为了表明这个方法能够将控制权让给消息循环。
线程方法没有这些不便之处。但是,async
-await
方法能够处理比线程方法更多的并发任务。这是怎么可能的呢?
对于每个并发任务,我们仍然有一个调用堆栈,只不过现在它是一个协程调用堆栈。我不太确定,但看起来这是关键差异:普通堆栈是操作系统堆栈,它们很昂贵,协程堆栈只是Python结构,它们要便宜得多。我的理解正确吗?
如果这是正确的,那么是否更好地将Python线程/调用堆栈与操作系统线程/调用堆栈分离,以使Python线程更便宜?
对不起,如果这个问题很蠢的话。我相信使用async
-await
方法有一些原因。只是想了解这些原因。
更新:
对于那些认为这个问题不好且太宽泛的人。
这里有一篇文章Unyielding——它以解释线程为何不好并推广async
方法开头。主旨:线程是邪恶的,很难确定一个可能从任意数量的线程同时执行的例程。
感谢 Nathaniel J. Smith(Python Trio库的作者)推荐这个链接。
顺便说一句,文章中的论点对我来说并不令人信服,但仍然可能有用。
threading.Lock
,尽管应用程序是基于async
的。代码的“关键部分”正在与外部应用程序通信,很重要的是,来自不同协程的请求系列不会在时间上重叠。因此,即使没有线程,同步问题也不会完全消失。 - lesnik