Python 如何在异步IO中复制线程代码?

Python 如何在异步IO中复制线程代码?,python,python-3.x,python-asyncio,python-multithreading,Python,Python 3.x,Python Asyncio,Python Multithreading,多年来我一直在使用线程,但它已经过时了,可能是出于很好的原因。因此,我试图理解这件事是如何运作的 我的线程解决方案 考虑下面的线程代码: 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(&

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

我的
线程解决方案
考虑下面的
线程
代码:

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
我用
asyncio尝试了什么
我现在尝试将其转换为
asyncio
,如下所示。我想出了

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(比如说_wait_10())
创建一个任务,该任务立即开始运行。
wait
相当于
threading.Thread.join()
,以确保主代码等待协同程序(或上例中的任务)有时间完成

输出是

from say_wait_10 start
from say_wait_10 end
from say
啊,所以任务中的代码是同步运行的,只有在完成之后,才会调用
say()
。异步部分在哪里

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

from say_wait_10 start
from say
我的问题 如何复制我的
线程
代码-我非常希望能够解释代码中发生了什么,以便在继续之前掌握
asyncio
的原理

或者,一个指向指导我从
threading
asyncio
的教程的指针会非常棒


如果这有帮助的话,我对JS中的承诺没有任何问题,尽管我对JS的理解非常肤浅(也就是说,比我在Python中的理解更肤浅——我只是一个业余开发人员)。在JS中,由于代码运行的位置,我不难想象“事情发生时就会发生,然后它们会更新DOM的某些部分(这是我的典型用法))等待是你的问题。
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.run()
,这样整个
asyncio
线程就可以启动了,这样我就不能启动类似于线程的东西了(这样做)然后继续我的同步代码。对,运行事件循环是一个阻塞操作。如果你想要一个后台线程在循环之外做一些事情,你应该看看
run\u in\u executor
。@WoJ Asyncio不是线程的替代品,它是一个不同的范例,要求整个程序都是wruser4815162342:我实际上只是在读你的另一个答案(在
run_in_executor
上)。我看到
异步IO
需要手动控制-在这个意义上,我不能有两个循环,每个
范围(10)内打印(I)
,同时启动,预期输出将是混合的。第一个循环需要完成,然后是另一个循环-因为我从未手动声明它可以“放手”让其他协程跳入(这与我没有任何控制的
线程化
完全不同)@WoJ是正确的,区别在于。最好将asyncio视为非常复杂的线程替代品,而不是(直接)线程替代品。