首先,tl;博士:
concurrent.futures
如果您使用的是 3.2+,请使用,或者如果您使用的是 2.x,则使用 PyPI 上向后移植相同内容的模块futures
。
您可以使用 a 编写代码并将其ThreadPoolExecutor
切换为 aProcessPoolExecutor
作为单行更改。而且 API 是如此的小而简单,没有什么可混淆的。
还要求命令异步执行操作不是一种选择,因为我希望机器人易于扩展。
我不明白这是怎么回事。异步代码并没有降低其可扩展性。当然,您必须知道如何编写异步代码才能对其进行扩展,但是成千上万的 JS 新手程序员每天都在做几乎可以完成的工作,而 Python 使它变得容易得多(请参阅monocle
、inlineCallbacks
in twisted
、tulip
等) .)。此外,您在描述中明确将这些东西称为“回调”这一事实意味着您已经在考虑这些术语……</p>
如果您确信这实际上是一项要求,那么twisted
是不可接受的。但是gevent
(和eventlet
,等等)可能是——你可以编写看起来完全同步的代码,并且它是异步运行的。
下一个:
您推荐使用哪个模块来并行运行这些回调中的几个,为什么?
你真的需要并行运行它们吗(你可以利用多个内核同时运行多个 CPU 密集型作业),同时运行(长时间运行的作业不会阻塞其他作业),或者两者都不需要(只要随着工作的完成,它们是并行化、交错式还是序列化都无关紧要)?
如果需要并行性,则需要multiprocessing
. 真的没有办法解决这个问题。GIL 将阻止您在单个进程中使用多个内核。
如果只需要并发,可以使用threading
或multiprocessing
。进程可能意味着在 Windows 和 Unix 之间(甚至有时在 Unix 之间)有更多的开销和/或更多的可移植性问题,并且它有时会迫使您考虑如何传递数据——或者,如果必须的话,共享它。另一方面,通过不强迫您考虑传递或共享数据,线程可以更容易地意外创建竞争和其他错误。(有关权衡的更多信息,请参见isedev 的最佳答案。)
如果您都不需要,您可以使用gevent
(或类似的东西)threading
、、或multiprocessing
。您可以像创建数百个线程或进程一样轻松地创建和切换 10000 个绿色线程,而且开销要少得多。但是,一个长时间运行的受 CPU 限制的命令可能会使您的整个系统停止运行。
无论您使用哪一个,您很可能都希望使用一组greenlet、线程或进程,将命令从队列中拉出(而不是为每个命令派生一个新命令,或者构建更复杂的东西)。
虽然multiprocessing
内置了这样的东西,threading
但没有。(实际上,有一个基于threading
- 的线程池——但它在 中multiprocessing
,而不是threading
。而且它不是公共 API 的一部分。)
中有很多非常酷的东西multiprocessing
,如果你需要,一定要使用它。(还有一些第三方库,其中包含更酷的东西,可以使复杂的用例变得更容易,或者做一些multiprocessing
不能做的事情。)但如果没有,那就futures
简单多了,而且能力用单行更改(甚至在运行时简单地进行)测试具有线程和进程的同一系统非常好。