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视为非常复杂的线程替代品,而不是(直接)线程替代品。