C # программист пытается выучить немного Python.Я пытаюсь запустить интенсивный процесс вычисления, позволяя асинхронному методу, связанному с вводом-выводом, тихонько перенести фоновый режим.В C # я обычно устанавливаю ожидаемый ход, затем запускаю код, интенсивно использующий процессор, затем жду задачу ввода-вывода и затем объединяю результаты.
Вот как я это сделаю в C #
static async Task DoStuff() {
var ioBoundTask = DoIoBoundWorkAsync();
int cpuBoundResult = DoCpuIntensizeCalc();
int ioBoundResult = await ioBoundTask.ConfigureAwait(false);
Console.WriteLine($"The result is {cpuBoundResult + ioBoundResult}");
}
static async Task<int> DoIoBoundWorkAsync() {
Console.WriteLine("Make API call...");
await Task.Delay(2500).ConfigureAwait(false); // non-blocking async call
Console.WriteLine("Data back.");
return 1;
}
static int DoCpuIntensizeCalc() {
Console.WriteLine("Do smart calc...");
Thread.Sleep(2000); // blocking call. e.g. a spinning loop
Console.WriteLine("Calc finished.");
return 2;
}
И вот эквивалентный код на python
import time
import asyncio
async def do_stuff():
ioBoundTask = do_iobound_work_async()
cpuBoundResult = do_cpu_intensive_calc()
ioBoundResult = await ioBoundTask
print(f"The result is {cpuBoundResult + ioBoundResult}")
async def do_iobound_work_async():
print("Make API call...")
await asyncio.sleep(2.5) # non-blocking async call
print("Data back.")
return 1
def do_cpu_intensive_calc():
print("Do smart calc...")
time.sleep(2) # blocking call. e.g. a spinning loop
print("Calc finished.")
return 2
await do_stuff()
Важно отметить, что задача с интенсивным использованием ЦП представлена блокирующим сном, которого нельзя ожидать, а задача, связанная с вводом-выводом, представлена неблокирующейожидаемый сон.
Это займет 2,5 секунды для запуска в C # и 4,5 секунды в Python.Разница в том, что C # сразу же запускает асинхронный метод, тогда как python запускает метод только тогда, когда он попадает в ожидание.Вывод ниже подтверждает это.Как я могу достичь желаемого результата.Код, который будет работать в Jupyter Notebook, будет признателен, если это вообще возможно.
--- C# ---
Make API call...
Do smart calc...
Calc finished.
Data back.
The result is 3
--- Python ---
Do smart calc...
Calc finished.
Make API call...
Data back.
The result is 3
Обновление 1
Вдохновленный ответом knh190, кажется, что я могу получить большинствопути туда, используя asyncio.create_task(...)
.Это достигает желаемого результата (2,5 с): во-первых, асинхронный код запускается;затем блокирующий код ЦП выполняется синхронно;в-третьих, ожидается асинхронный код;наконец результаты объединены.Чтобы асинхронный вызов действительно начал работать, мне нужно было ввести await asyncio.sleep(0)
, что выглядит как ужасный хак.Можем ли мы поставить задачу на выполнение без этого?Должен быть лучший способ ...
async def do_stuff():
task = asyncio.create_task(do_iobound_work_async())
await asyncio.sleep(0) # <~~~~~~~~~ This hacky line sets the task running
cpuBoundResult = do_cpu_intensive_calc()
ioBoundResult = await task
print(f"The result is {cpuBoundResult + ioBoundResult}")