xxb*_*bcc 17 .net c# asynchronous async-await
抱歉,这是一个愚蠢的问题(或重复的问题)。
我有一个功能A:
public async Task<int> A(/* some parameters */)
{
var result = await SomeOtherFuncAsync(/* some other parameters */);
return (result);
}
Run Code Online (Sandbox Code Playgroud)
我有另一个函数B,调用A但不使用返回值:
public Task B(/* some parameters */)
{
var taskA = A(/* parameters */); // #1
return (taskA);
}
Run Code Online (Sandbox Code Playgroud)
请注意,B没有声明async,也没有等待对的调用A。对的呼叫A不是“一劳永逸”的呼叫- B的调用方式C如下:
public async Task C()
{
await B(/* parameters */);
}
Run Code Online (Sandbox Code Playgroud)
请注意,在#1处没有await。我有一个同事声称这使调用A同步,并且他不断Console.WriteLine提出看起来似乎证明了自己观点的日志。
我试图指出这是因为我们不等待内部结果B,而是等待任务链,并且内部代码的性质A也不会因为我们不等待而改变。由于A不需要from的返回值,因此只要链中有人等待它,就无需在调用站点等待该任务(发生在中C)。
我的同事非常执着,我开始怀疑自己。我的理解错了吗?
Eri*_*ert 28
如果这是一个愚蠢的问题,我很抱歉
这不是一个愚蠢的问题。这是一个重要的问题。
我有一个同事声称这使对A的调用是同步的,并且他不断提出Console.WriteLine日志,这似乎证明了他的观点。
那是那里的根本问题,您需要教育您的同事,以免他们误导自己和他人。没有异步调用之类的东西。该呼叫是不是是异步的,东西永远。跟我说 调用在C#中不是异步的。在C#中,当您调用函数时,在计算完所有参数后立即调用该函数。
如果您的同事或您认为存在异步调用之类的事情,那么您就痛苦不堪,因为您对异步工作原理的信念将与现实脱节。
那么,您的同事正确吗?当然可以。调用A是同步的,因为所有函数调用都是同步的。但是,他们相信存在诸如“异步调用”之类的事实,这意味着他们对C#中异步的工作方式有严重的误解。
如果您的同事特别认为以await M()某种方式发出了M()“异步” 的呼吁,那么您的同事就会产生很大的误解。 await是运算符。可以肯定,它是一个复杂的运算符,但它是一个运算符,并且对值进行运算。 await M()而且var t = M(); await t;是同一回事。等待操作发生在调用之后,因为await 操作返回的值。 await是NOT到编译器“产生到M()异步调用”或任何这样的事情的指令; 没有所谓的“异步调用”。
如果这是他们错误信念的本质,那么您就有机会教育您的同事有关什么await意思。 await意味着简单但功能强大。它的意思是:
Task我正在操作。Task这就是全部await。它只是检查任务的内容,如果任务不完整,它会说:“好吧,在完成该任务之前,我们无法在该工作流程上取得任何进展,因此请返回给我的调用方,它将为该CPU找到其他内容去做”。
A中代码的性质不会因为我们不等待而改变。
没错 我们同步调用A,并返回Task。直到A返回,呼叫站点之后的代码才运行。有趣的A是,A允许将不完整的返回Task给调用方,并且该任务表示异步工作流中的一个节点。工作流已经是异步的,并且正如您所注意到的,它A与返回后的返回值无关。A不知道您是否要await返回Task。 A它会尽可能长时间地运行,然后返回正常完成的任务或异常完成的任务,或者返回不完整的任务。但是您在呼叫站点上所做的任何事情都无法改变这一点。
由于不需要A的返回值,因此无需在呼叫站点等待任务
正确。
只要链上的某人等待任务(在C中发生),就无需在调用站点等待任务。
现在你失去了我。为什么有人必须等待Task归还者A? 说为什么你认为有人需要到await那个Task,是因为你可能有一个错误的信念。
我的同事非常执着,我开始怀疑自己。我的理解错了吗?
您的同事几乎可以肯定是错误的。您的分析似乎是正确的权利,直到您说是有位的要求,每一个Task被await编,这是不正确的。这是奇怪的不await一个Task,因为这意味着你写的,你开始的操作,并且不关心它是如何完成时或程序,它肯定味道不好写一个这样的程序,但没有一个要求,以await每Task。如果您相信存在,请再说一次该信念,我们将对其进行整理。
你是对的。创建任务只是这样做,它并不关心何时以及谁将等待其结果。尝试放入await Task.Delay(veryBigNumber);,SomeOtherFuncAsync控制台输出应该是您期望的。
这称为消除(eliding),我建议您阅读此博客文章,在这里您可以了解为什么应该或不应该这样做。
还有一些复制代码的最小示例(证明有点麻烦):
class Program
{
static async Task Main(string[] args)
{
Console.WriteLine($"Start of main {Thread.CurrentThread.ManagedThreadId}");
var task = First();
Console.WriteLine($"Middle of main {Thread.CurrentThread.ManagedThreadId}");
await task;
Console.WriteLine($"End of main {Thread.CurrentThread.ManagedThreadId}");
}
static Task First()
{
return SecondAsync();
}
static async Task SecondAsync()
{
await ThirdAsync();
}
static async Task ThirdAsync()
{
Console.WriteLine($"Start of third {Thread.CurrentThread.ManagedThreadId}");
await Task.Delay(1000);
Console.WriteLine($"End of third {Thread.CurrentThread.ManagedThreadId}");
}
}
Run Code Online (Sandbox Code Playgroud)
这Middle of main之前End of third写过,证明它实际上是异步的。此外,您可以(最有可能)看到函数的末端与程序的其余部分在不同的线程上运行。main的开头和中间始终将在同一线程上运行,因为它们实际上是同步的(main开始,调用函数链,第三个返回(它可能在与await关键字所在的行返回)),然后main继续,就好像有await这两个函数的关键字后面的结尾都可以在ThreadPool中的任何线程上运行(或在您使用的同步上下文中)。
现在有趣的是,如果Task.Delayin Third花费的时间不很长并且实际上是同步完成的,那么所有这些都将在单个线程上运行。而且,即使它可以异步运行,也可能全部在单个线程上运行。没有规则说明异步函数将使用多个线程,它很可能只是在等待某些I / O任务完成的同时做其他工作。
| 归档时间: |
|
| 查看次数: |
549 次 |
| 最近记录: |