【发布时间】:2019-10-08 06:35:04
【问题描述】:
C# 程序员试图学习一些 Python。我正在尝试运行 CPU 密集型计算,同时让 IO 绑定异步方法在后台悄悄地消失。在 C# 中,我通常会设置 awaitable,然后启动 CPU 密集型代码,然后等待 IO 任务,然后合并结果。
这是我在 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()
重要的是,请注意,CPU 密集型任务由无法等待的阻塞睡眠表示,IO 绑定任务由可等待的非阻塞睡眠表示。
在 C# 中运行需要 2.5 秒,在 Python 中运行需要 4.5 秒。不同之处在于 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 秒):首先,异步代码设置为运行;接下来,阻塞CPU代码同步运行;第三,等待异步代码;最后合并结果。为了让异步调用真正开始运行,我必须输入一个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}")
【问题讨论】:
标签: python async-await jupyter-notebook