【问题标题】:How to replicate threading code in asyncio?如何在 asyncio 中复制线程代码?
【发布时间】:2021-02-01 04:55:07
【问题描述】:

我多年来一直在使用threading,但它已经过时了,可能有很好的理由。因此,我试图了解这件事是如何运作的。

我的解决方案是threading

考虑下面的threading 代码:

import threading
import time

def say_wait_10():
    print("from say_wait_10 start")
    time.sleep(10)
    print("from say_wait_10 end")

def say():
    print("from say")

threading.Thread(target=say_wait_10).start()
threading.Thread(target=say).start()

这个想法是启动一个需要时间的任务 (say_wait_10()),让它自己运行,同时启动一个短暂的任务 (say()),它也可以自己运行。它们是独立的,一个不会阻塞另一个(这可能或多或少有效,具体取决于任务是 CPU 密集型还是 I/O 密集型)。

输出如预期的那样

from say_wait_10 start
from say
from say_wait_10 end

我对@9​​87654329@ 的尝试

我现在尝试将其转换为asyncio,遵循documentation。我想出了

import asyncio

async def say_wait_10():
    print("from say_wait_10 start")
    await asyncio.sleep(10)
    print("from say_wait_10 end")

async def say():
    print("from say")

async def main():
    await asyncio.create_task(say_wait_10())
    await asyncio.create_task(say())

asyncio.run(main())

我对上面代码的理解是asyncio.create_task(say_wait_10()) 创建了一个立即开始自行运行的任务。 await 等同于 threading.Thread.join(),以确保主代码等待协程(或上例中的任务)有时间​​完成。

输出是

from say_wait_10 start
from say_wait_10 end
from say

啊,所以任务中的代码同步运行,只有在它完成之后,say() 才被调用。这其中的异步部分在哪里?

然后我想也许await实际上意味着“等待”(让任务在继续之前完成)所以我删除了它,但这只是启动了程序,在执行期间运行了任何可运行的东西主程序,然后就结束了

from say_wait_10 start
from say

我的问题

如何复制我的 threading 代码 - 我非常感谢您对代码中发生的事情的解释,以便我在继续之前能够掌握 asyncio 的理念。

另外,一个指向可以引导我从 threadingasyncio 的教程的指针会很棒。

注意

如果这有帮助,我对 JS 中的 Promises 的想法没有任何问题,尽管对 JS 的理解非常肤浅(也就是说,比我在 Python 中的理解更肤浅——我只是一个业余开发者) .在 JS 中,由于代码运行的位置,我没有任何问题可以想象“事情发生时发生,然后它们会更新 DOM 的某些部分(这是我的典型用途))

【问题讨论】:

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


    【解决方案1】:

    awaits 是您的问题。 await 处于阻塞状态,因此您不要安排 say 直到 say_wait_10 之后。有几种方法可以实现您想要的。

    第一个是一些变化

    task = create_task(say_wait_10())
    await say()
    await task
    

    如果您有两个以上的任务,并且对它们花费的时间控制较少,这会有点混乱。另一个选项是

    await gather(say_wait_10(), say())
    

    【讨论】:

    • 谢谢 - gather 确实有效。那么这是否相当于threading 中的start()join() 的组合? (从功能的角度来看,我知道asyncio 在单线程中运行)。在我的情况下,这实际上会导致代码更短。问题是需要asyncio.run() 以便整个asynciothread 启动,所以我不能拥有像我启动的线程(并且它会做事情)并继续我的同步代码。
    • 对,运行事件循环是一个阻塞操作。如果你想要一个在循环之外做某事的后台线程,你应该看看run_in_executor
    • @WoJ Asyncio 不是线程的替代品,它是一种不同的范式,需要编写整个程序以便观察它。
    • @user4815162342:我实际上只是在阅读您的另一个答案(run_in_executor)。我看到asyncio 需要手动控制——从某种意义上说,我不能有两个循环,每个print(i)for i in range(10) 中同时启动,并期望输出会混合。第一个循环需要完成,然后是另一个循环 - 因为我从不手动声明它可以“放手”让其他协程跳入(这与我没有任何控制权的 threading 完全不同)跨度>
    • @WoJ 正确,区别是intentional。最好将 asyncio 视为 twisted 的非常复杂的替代品,而不是线程的(直接)替代品。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-04
    • 2020-11-02
    • 1970-01-01
    • 2018-02-10
    • 1970-01-01
    • 1970-01-01
    • 2014-05-26
    相关资源
    最近更新 更多