【发布时间】:2017-07-31 10:59:02
【问题描述】:
在同一个 python 项目中同时使用 asyncio 和 threading 是否有意义,以便代码在不同的线程中运行,其中一些 asyncio 用于获取异步活动的顺序查找代码?
或者尝试这样做意味着我缺少关于线程或异步使用的一些基本概念?
【问题讨论】:
标签: python-3.x python-multithreading python-asyncio
在同一个 python 项目中同时使用 asyncio 和 threading 是否有意义,以便代码在不同的线程中运行,其中一些 asyncio 用于获取异步活动的顺序查找代码?
或者尝试这样做意味着我缺少关于线程或异步使用的一些基本概念?
【问题讨论】:
标签: python-3.x python-multithreading python-asyncio
当然,这可能是有道理的。
异步代码原则上在同一个线程中运行一堆例程。
这意味着当一个例程必须等待输入或输出 (I/O) 时,它将暂时停止该例程并简单地开始处理另一个例程,直到它在那里遇到等待,等等。
多线程(或“并行”代码)原则上同时在您机器的不同内核上运行。 (请注意,在 Python 中,并行处理是通过使用下面@Yassine Faris 指出的多个进程来实现的。
在同一个程序中同时使用两者可能非常有意义。使用 asyncio 以便在等待 I/O 时继续处理。使用多线程(Python 中的多处理)来执行,例如,在程序的另一部分并行执行大量计算。
【讨论】:
我不明白你在问什么(关于“按顺序查找异步活动的代码”的部分),但由于没有答案,我会写一些想法。
让我们谈谈为什么我们需要 asyncio/threads。假设我们有一个任务要发出两个请求。
如果我们将使用普通的单线程非异步代码,我们唯一的选择 是请求一个 url 并且只有在它完成之后 - 对于 另一个:
request(url1)
request(url2)
这里的问题是我们的工作效率低下:每个函数在执行的大部分时间里什么都不做,只是等待网络结果。如果我们能够以某种方式将 CPU 用于第二个请求,而第一个请求却卡在网络上并且不需要它,那将是很酷的。
这个问题可以通过在不同线程中运行函数来解决(通常也能解决):
with ThreadPoolExecutor(max_workers=2) as e:
e.submit(request, url1)
e.submit(request, url2)
通过这种方式,我们可以更快地获得结果。当第一个请求被网络卡住时,CPU 将能够为另一个线程中的第二个请求做一些有用的事情。
然而,这不是理想的解决方案:线程之间的切换需要一些成本,执行流程比第一个示例更复杂。
应该会有更好的方法。
使用一个函数空闲期开始执行另一个函数是 asyncio 的一般意义:
await asyncio.gather(
async_request(url1),
async_request(url2),
)
事件循环管理执行流程:当第一个协程到达某个 I/O 操作并且 CPU 可以用于其他地方的工作时,第二个协程启动。稍后的事件循环返回以继续执行第一个协程。
我们得到“并行”请求和清晰易懂的代码。由于我们在单线程中进行了并行化,因此我们不需要另一个。
实际上,当我们使用 asyncio 时,线程仍然很有用。如果我们愿意为他们付费,他们可以help我们快速将同步 I/O 函数转换为异步:
async def async_request(url):
loop = asyncio.get_event_loop()
return (await loop.run_in_executor(None, request, url))
但同样,它是可选的,我们通常可以找到模块来异步发出请求(和其他 I/O 任务)而无需线程。
当线程在异步程序中有用时,我没有遇到任何其他任务。
【讨论】: