最近,我似乎对C#5.0 的惊人异步等待模式不够了解。我这辈子去哪了
我对简单的语法感到非常兴奋,但是我遇到了一个小困难。我的问题是异步函数的声明与常规函数完全不同。由于只有异步函数可以等待其他异步函数,因此当我尝试将一些旧的阻止代码移植到异步时,我产生了必须转换的函数的多米诺骨牌效应。
人们一直称其为僵尸大批出没。当异步在您的代码中被咬时,它将不断变得越来越大。移植过程并不困难,只需将其async
放入声明中并用来包装返回值Task<>
。但是在移植旧的同步代码时,一遍又一遍地执行此操作很烦人。
在我看来,如果两种函数类型(异步和普通旧同步)具有完全相同的语法,那将是自然得多的。如果是这种情况,移植将花费零的精力,我可以在两种形式之间轻松切换。
我认为如果遵循以下规则,这可能会起作用:
异步函数不再需要
async
声明。他们的返回类型不必包装Task<>
。编译器将在编译期间自行识别异步函数,并根据需要自动执行Task <>包装。不再需要对异步函数进行“一劳永逸”的调用。如果要调用异步函数,则需要等待它。无论如何,我几乎都不用一劳永逸,疯狂的比赛条件或僵局的所有例子似乎总是基于它们。我认为他们与我们试图利用的同步思维过于混乱和“脱节”。
如果您真的不能一劳永逸,那将有特殊的语法。无论如何,它不会成为我正在谈论的简单统一语法的一部分。
您需要表示异步调用的唯一关键字是
await
。如果您正在等待,则该调用是异步的。如果您不这样做,则该呼叫是普通的老式同步呼叫(请记住,我们不再具有即兴即弃的功能)。编译器将自动识别异步函数(因为它们不再有特殊的声明了)。规则4使得此操作非常简单-如果函数
await
内部有调用,则它是异步的。
能行吗?还是我错过了什么?这种统一的语法更加流畅,可以完全解决僵尸的侵扰。
一些例子:
// assume this is an async function (has await calls inside)
int CalcRemoteBalanceAsync() { ... }
// assume this is a regular sync function (has no await calls inside)
int CalcRemoteBalance() { ... }
// now let's try all combinations and see what they do:
// this is the common synchronous case - it will block
int b1 = CalcRemoteBalance();
// this is the common asynchronous case - it will not block
int b2 = await CalcRemoteBalanceAsync();
// choosing to call an asynchronous function in a synchronous manner - it will block
// this syntax was used previously for async fire-and-forget, but now it's just synchronous
int b3 = CalcRemoteBalanceAsync();
// strange combination - it will block since it's calling a synchronous function
// it should probably show a compilation warning though
int b4 = await CalcRemoteBalance();
注意:这是SO中有趣的相关讨论的延续
await
立即进行操作。你可以做类似的事情var task = FooAsync(); Bar(); await task;
。在您的提案中我将如何处理?
async
。我认为这是的一大优势async
- await
:它可以让您轻松撰写异步操作(而不仅仅是简单的“启动,等待,启动B,等待B”的方式)。并且已经有专门用于此目的的特殊语法:称为await
。