使用asyncio和线程

时间:2017-07-31 10:59:02

标签: python-3.x python-multithreading python-asyncio

在同一个python项目中同时使用asyncio和线程是否有意义,以便代码在不同的线程中运行,其中一些是asyncio用于获取异步活动的顺序代码?

或试图这样做是否意味着我错过了使用线程或asyncio的一些基本概念?

2 个答案:

答案 0 :(得分:1)

当然可能有意义。

异步代码原则上在同一个线程中运行一堆例程。

这意味着当一个例程必须等待输入或输出(I / O)时,它将暂时停止该例程,并简单地开始处理另一个例程,直到遇到等待,等等。

多线程(或"并行化"代码)原则上同时在您机器的不同内核上运行。 (请注意,在Python中,并行处理是通过使用@Yassine Faris在下面指出的多个进程实现的。)

在同一个程序中使用它们可能是完全合理的。使用asyncio以便在等待I / O时保持处理。使用多线程(Python中的多处理)可以在程序的另一部分中并行执行繁重的计算。

答案 1 :(得分:0)

我不明白你在问什么(部分是关于“顺序查找异步活动的代码”),但由于没有答案,我会写一些想法。

让我们来谈谈为什么我们需要asyncio / threads。想象一下,我们有一个任务要做两个请求。

  1. 如果我们将使用普通的单线程非异步代码,那么我们只能选择 是要求一个网址,只有在它完成后 - 为 另一:

    request(url1)
    request(url2)
    

    这里的问题是我们的工作无效:每个函数执行的大部分时间都不会等待网络结果。如果我们以某种方式能够使用CPU作为第二个请求,而第一个请求使用网络内容并且不需要它,那将会很酷。

  2. 通过在不同的线程中运行函数,可以解决(通常可以解决)这个问题:

    with ThreadPoolExecutor(max_workers=2) as e:
        e.submit(request, url1)
        e.submit(request, url2)
    

    我们会以这种方式更快地获得结果。当第一个请求被网络困住时,CPU可以为另一个线程中的第二个请求做一些有用的事情。

    然而,这不是理想的解决方案:在线程之间切换有一些成本,执行流程比第一个例子更复杂。

    应该有更好的方法。

  3. 使用一个函数空闲时段开始执行另一个函数是asyncio一般的关于:

    await asyncio.gather(
        async_request(url1),
        async_request(url2),
    )
    

    事件循环管理执行流程:当第一个协同程序达到某些I / O操作并且CPU可用于在其他地方执行工作时,第二个协同程序启动。后来的事件循环返回以继续执行第一个协同程序。

    我们获得“并行”请求并清除可理解的代码。由于我们在单线程中有并行化,我们只是不需要另一个。

  4. 实际上,当我们使用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任务)的模块。

    当线程在异步程序中很有用时,我没有遇到任何其他任务。