I'm working with some asyncio Python code and I encountered a problem with sequencing of coroutines. I have some experience with C#, so I will use it as an example.
In C# I can write:
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
}
}
Which results in the following, notice the start of coroutines matches the call order, not the wait order. This is guaranteed due to how the coroutine functions are partitioned into a generator. I.e. they always run synchronously until the first await.
Foo start 1
Foo start 2
Foo end 2
Foo end 1
But when I do the same thing in Python I get different order.
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
I also know why this is - because foo(1,300) returns a generator which does not start until the coroutine is awaited/scheduled.
My question is how to achieve C#-like behaviour in Python, meaning the coroutines start as they are called without interruption until first await?
I've tried
t1 = asyncio.create_task(foo(1,300))
t2 = asyncio.create_task(foo(2,200))
which fixed the issue but is the scheduling order really guaranteed?