我什么时候应该在常规线程上使用 asyncio,为什么?它是否提供性能提升?

When should I be using asyncio over regular threads, and why? Does it provide performance increases?

我对 Python 中的多线程有非常基本的了解,对 asyncio 的了解甚至更基本。

我目前正在编写一个基于 Curses 的小程序(最终将使用完整的 GUI,但那是另外一回事了),它处理 UI 和主要的用户 IO线程,然后有另外两个守护线程(每个都有自己的 queue/worker-method-that-gets-things-from-a-queue):

所有三个线程都连续运行并发,这引出了一些问题:

谢谢!

When the worker thread's queue (or, more generally, any thread's queue) is empty, should it be stopped until is has something to do again, or is it okay to leave continuously running? Do concurrent threads take up a lot of processing power when they aren't doing anything other than watching its queue?

您应该只对 queue.get() 使用阻塞调用。这将使线程阻塞在 I/O,这意味着 GIL 将被释放,并且不会使用任何处理能力(或至少是非常小的数量)。不要在 while 循环中使用非阻塞获取,因为这将需要更多 CPU 次唤醒。

Should the two threads' queues be combined? Since the watcher thread is continuously running a single method, I guess the worker thread would be able to just pull tasks from the single queue that the watcher thread puts in.

如果观察者所做的只是将事物从队列中取出并立即将其放入另一个队列,在那里它被单个工作人员使用,这听起来像是不必要的开销 - 你也可以直接使用它工人。不过,如果是这种情况,我不太清楚 - 观察者 从队列中消费 ,还是只是将项目放入其中?如果它从队列中消费,谁在往里面放东西?

I don't think it'll matter since I'm not multiprocessing, but is this setup affected by Python's GIL (which I believe still exists in 3.4) in any way?

是的,这是受 GIL 的影响。一次只有一个线程可以 运行 Python 字节码,因此不会获得真正的并行性,除非线程 运行ning I/O (这会释放 GIL) .如果您的工作线程正在执行 CPU 绑定活动,您应该认真考虑 运行 如果可能的话,通过 multiprocessing 在一个单独的进程中使用它。

Should the watcher thread be running continuously like that? From what I understand, and please correct me if I'm wrong, asyncio is supposed to be used for event-based multithreading, which seems relevant to what I'm trying to do.

不好说,因为我不知道"running continuously"到底是什么意思。它在不断地做什么?如果它大部分时间都在休眠或阻塞在 queue 上,那很好 - 这两件事都会释放 GIL。如果它一直在做实际工作,那将需要 GIL,因此会降低应用程序中其他线程的性能(假设它们试图同时工作)。 asyncio 是为 I/O 绑定的程序设计的,因此可以 运行 在 线程中,使用异步 I/O .听起来你的程序可能很适合,这取决于你的 worker 在做什么。

The main thread is basically always just waiting for the user to press a key to access a different part of the menu. This seems like a situation asyncio would be perfect for, but, again, I'm not sure.

任何您主要等待 I/O 的程序都可能适合 asyncio - 但前提是您可以找到一个生成 curses 的库(或您最终使用的任何其他 GUI 库)选择)与它一起玩得很好。大多数 GUI 框架都带有自己的事件循环,这将与 asyncio 的冲突。您需要使用一个库来使 GUI 的事件循环与 asyncio 的事件循环很好地配合。您还需要确保可以找到您的应用程序使用的任何其他基于同步 I/O 的库(例如数据库驱动程序)的 asyncio 兼容版本。

也就是说,从基于线程的程序切换到基于 asyncio 的程序,您不太可能看到任何性能改进。它的性能可能大致相同。由于您只处理 3 个线程,因此它们之间的上下文切换开销不是很大,因此从单线程、异步 I/O 方法切换不会产生很大差异。 asyncio 将帮助您避免线程同步的复杂性(如果这是您的应用程序的问题 - 目前尚不清楚),并且至少在理论上,如果您的应用程序可能需要 lots 个线程,但事实并非如此。我认为对你来说,这基本上取决于你喜欢哪种编码风格(假设你可以找到你需要的所有 asyncio 兼容库)。