【发布时间】:2014-07-05 20:08:52
【问题描述】:
我对这个主题很困惑。我的假设是任务创建和它的调度应该严格分开,在 C# 中不是这种情况。
考虑下面的简单代码。
static async Task simpleton()
{
print("simpleton");
}
static async Task cont()
{
print("cont");
}
static void Main(string[] args)
{
Task t1 = simpleton();
Task t2 = t1.ContinueWith((a) => { cont(); });
Thread.Sleep(1000);
return;
}
输出是
simpleton
cont
simpleton 函数运行并创建任务 t1(已经完成)——没关系。然而,t2 接缝(至少在代码中)仅是任务创建 - 系统没有要求调度,那么为什么以及谁安排继续运行?显然这里的创建/运行原则被打破了。
await 也有类似的情况。考虑一下这个众所周知的article 中的伪代码。根据伪代码 await 被翻译成延续任务并返回给调用者,我希望必须安排任务才能完成它。也不是这种情况,请考虑以下代码:-
static async Task foo()
{
await bar();
}
static async Task bar()
{
print("bar");
}
static void Main(string[] args)
{
foo();
Thread.Sleep(1000);
return;
}
bar 将在没有专门调度 foo 创建的 Task 对象的情况下执行。
所以问题是:
ContinueWith 不仅创建任务而且安排任务是否正确。
await 不仅会创建文章中显示的继续任务,而且如果可能的话还可以调度(Call Post on SynchronizationContext 或 TaskScheduler)是否正确。
为什么这种设计(调度和创建混合)被 async/await 语言设计者采用?
【问题讨论】:
-
您的样本是完全同步的 - 所以所有部分都是同步执行的。使用
async关键字不会神奇地将同步代码变为异步代码。使用Task.Delay(1000)或类似代码来实际拥有异步代码。 -
@Alexei 这是否同步无关紧要。问题是为什么它们(cont & bar)会被执行。您可以轻松地将其转换为异步案例,但问题将保持不变。谁安排功能。
-
“时间表”?您调用函数 (
foo()) 并执行它 - 有什么令人惊讶的?也许你想了解async是如何实现的——试试这个搜索bing.com/search?q=c%23+async+internals -
@Boris,您仍然可以安排由
async方法创建的任务,例如this,虽然很少需要。
标签: c# .net multithreading asynchronous async-await