我正在处理一些 asyncio Python 代码,我遇到了协程排序问题。我有一些使用 C# 的经验,所以我将使用它作为示例。
在 C# 中我可以写:
using System;
using System.Threading.Tasks;
public class Program
{
async static Task<int> foo(int n, int delay)
{
Console.WriteLine("Foo start {0}",n);
await Task.Delay(delay);
Console.WriteLine("Foo end {0}",n);
return 0;
}
public static void Main()
{
Task<int> t1 = foo(1,300);
Task<int> t2 = foo(2,200);
Task.WaitAll(new []{t2,t1});// Reverse on purpose
}
}
结果如下,注意协程的开始与调用顺序相匹配,不是等待顺序。由于协程函数如何划分到生成器中,因此可以保证这一点。 IE。它们总是同步运行,直到第一个 await
。
Foo start 1
Foo start 2
Foo end 2
Foo end 1
但是当我在 Python 中做同样的事情时,我得到不同的顺序。
import asyncio
async def foo(n,delay):
print(f"Foo start {n}")
await asyncio.sleep(delay/1000)
print(f"Foo end {n}")
return 0
async def main():
t1 = foo(1,300)
t2 = foo(2,200)
await asyncio.gather(t2,t1) # Reverse on purpose
asyncio.run(main())
Foo start 2
Foo start 1
Foo end 2
Foo end 1
我也知道这是为什么 - 因为 foo(1,300)
返回一个生成器,该生成器在等待/安排协程之前不会启动。
我的问题是如何在 Python 中实现类似 C# 的行为,这意味着协程会在调用时不间断地启动,直到第一次await
?
我试过了
t1 = asyncio.create_task(foo(1,300))
t2 = asyncio.create_task(foo(2,200))
哪个解决了这个问题,但调度顺序真的有保证吗?
最佳答案
asyncio.create_task()
,顾名思义,创建一个task.Task
实例。任务在 task.Task
的构造函数中安排
self._loop.call_soon(self.__step, context=self._context)
来自 BaseEventLoop.call_soon
的文档字符串:
Arrange for a callback to be called as soon as possible. This operates as a FIFO queue: callbacks are called in the order in which they are registered. Each callback will be called exactly once.
因此,只要您使用的事件循环不会覆盖此行为,我会说您可以按照您想要的方式使用 create_task
。据我所知,asyncio
中的事件循环都没有。
关于python - 如何像在 C# 中一样同步运行 Python 协程,直到第一次等待?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70448827/