不等待异步调用仍然是异步的,对吗? [英] Not awaiting an async call is still async, right?

查看:61
本文介绍了不等待异步调用仍然是异步的,对吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

很抱歉,这是一个愚蠢的问题(或重复的问题)。

I'm sorry if this is a silly question (or a duplicate).

我有一个函数 A

public async Task<int> A(/* some parameters */)
{
    var result = await SomeOtherFuncAsync(/* some other parameters */);

    return (result);
}

我还有另一个函数 B ,调用 A ,但不使用返回值:

the I have another function B, calling A but not using the return value:

public Task B(/* some parameters */)
{
    var taskA = A(/* parameters */); // #1

    return (taskA);
}

请注意, B 没有声明为 async ,并且没有等待对 A 的调用。对 A 的呼叫不是即兴即忘的呼叫- B 的呼叫由进行C 像这样:

Note that B is not declared async and is not awaiting the call to A. The call to A is not a fire-and-forget call - B is called by C like so:

public async Task C()
{
    await B(/* parameters */);
}

请注意,在#1 ,没有等待。我有一个同事声称,这使对 A 的调用同步进行,并且他不断提出 Console.WriteLine 日志似乎证明了他的观点。

Notice that at #1, there's no await. I have a coworker that claims that this makes the call to A synchronous and he keeps coming up with Console.WriteLine logs that seemingly prove his point.

我试图指出,只是因为我们不等待任务链 B 中的结果, em>已经被等待, A 中的代码的性质并没有因为我们不等待而改变。由于不需要 A 的返回值,因此只要链中有人等待它,就不必在调用站点等待任务。 >(发生在 C 中。)

I tried pointing out that just because we don't wait for the results inside B, the task chain is awaited and the nature of the code inside A doesn't change just because we don't await it. Since the return value from A is not needed, there's no need to await the task at the call site, as long as someone up the chain awaits it (which happens in C).

我的同事非常执着,我开始怀疑自己。我的理解不对吗?

My coworker is very insistent and I began to doubt myself. Is my understanding wrong?

推荐答案


很抱歉,这是一个愚蠢的问题

I'm sorry if this is a silly question

这不是一个愚蠢的问题。这是一个重要的问题。

It is not a silly question. It is an important question.


我有一个同事声称这使对A的调用是同步的,并且他不断提出Console。似乎证明了他的观点的WriteLine日志。

I have a coworker that claims that this makes the call to A synchronous and he keeps coming up with Console.WriteLine logs that seemingly prove his point.

这是根本的问题,您需要教育同事,以便他们停止误导自己和他人。 没有异步调用之类的东西通话不是异步的,永远。跟我说在C#中调用不是异步的。在C#中,调用函数时,在计算完所有参数后立即调用该函数

That is the fundamental problem right there, and you need to educate your coworker so that they stop misleading themselves and others. There is no such thing as an asynchronous call. The call is not the thing that is asynchronous, ever. Say it with me. Calls are not asynchronous in C#. In C#, when you call a function, that function is called immediately after all the arguments are computed.

如果您的同事或您认为存在异步调用之类的事情,那么您将痛苦不堪,因为您对异步工作原理的信念非常强烈与现实脱节。

If your coworker or you believes that there is such a thing as an asynchronous call, you are in for a world of pain because your beliefs about how asynchrony works will be very disconnected from reality.

那么,您的同事正确吗?当然是。 A 的调用是同步的,因为所有函数调用都是同步的。但是,他们相信存在异步调用之类的事实,这意味着他们对C#中异步的工作方式有严重的误解。

So, is your coworker correct? Of course they are. The call to A is synchronous because all function calls are synchronous. But the fact that they believe that there is such a thing as an "asynchronous call" means that they are badly mistaken about how asynchrony works in C#.

如果您的同事特别认为等待M()会以某种方式使 M()调用异步,那么您的同事就会误解。 等待运算符。可以肯定,它是一个复杂的运算符,但是它是一个运算符,并且对值进行运算。 等待M() var t = M();等待t; 是同一件事。等待发生在调用之后 ,因为等待 对返回的值进行操作 await 的指令,指示编译器生成对M()的异步调用或任何此类事物;

If specifically your coworker believes that await M() somehow makes the call to M() "asynchronous", then your coworker has a big misunderstanding. await is an operator. It's a complicated operator, to be sure, but it is an operator, and it operates on values. await M() and var t = M(); await t; are the same thing. The await happens after the call because the await operates on the value that is returned. await is NOT an instruction to the compiler to "generate an asynchronous call to M()" or any such thing; there is no such thing as an "asynchronous call".

如果这是他们错误信念的本质,那么您就有机会教育您的同事等待的含义。 等待意味着简单但功能强大。这意味着:

If that is the nature of their false belief, then you've got an opportunity to educate your coworker as to what await means. await means something simple but powerful. It means:


  • 看一下我正在执行的任务

  • 如果任务异常完成,则抛出该异常

  • 如果任务正常完成,请提取该值并使用它

  • 如果任务未完成,请将该方法的其余部分注册为等待的任务的继续,然后返回 new Task 代表此呼叫的我的呼叫者的异步工作流。

  • Look at the Task that I'm operating on.
  • If the task is completed exceptionally, throw that exception
  • If the task is completed normally, extract that value and use it
  • If the task is incomplete, sign up the remainder of this method as the continuation of the awaited task, and return a new Task representing this call's incomplete asynchronous workflow to my caller.

等待完成的所有操作。它只是检查任务的内容,如果任务不完整,它会说:好吧,在该任务完成之前,我们无法在此工作流程上取得任何进展,因此请返回给我的调用方,它将为该CPU找到其他内容

That's all that await does. It just examines the contents of a task, and if the task is incomplete, it says "well, we can't make any progress on this workflow until that task is complete, so return to my caller who will find something else for this CPU to do".


A中代码的性质不会因为我们不等待而改变。

the nature of the code inside A doesn't change just because we don't await it.

是正确的。我们同步调用 A ,它返回一个 Task 。返回 A 之前,呼叫站点之后的代码不会运行。关于 A 的有趣之处在于,允许 A 返回不完整的 Task 调用方,该任务表示异步工作流程中的一个节点。工作流已经 是异步的,并且您已经注意到,它对 A 的返回值之后没什么影响返回; A 不知道您是否要等待返回的任务还是不。 A 会一直运行,然后返回正常完成的任务或异常完成的任务,或者返回不完整的任务。但是,您在呼叫站点所做的任何更改都不会改变。

That's correct. We synchronously call A, and it returns a Task. The code after the call site does not run until A returns. The interesting thing about A is that A is allowed to return an incomplete Task to its caller, and that task represents a node in an asynchronous workflow. The workflow is already asynchronous, and as you note, it makes no difference to A what you do with its return value after it returns; A has no idea whether you are going to await the returned Task or not. A just runs as long as it can, and then either it returns a completed-normally task, or a completed-exceptionally task, or it returns an incomplete task. But nothing you do at the call site changes that.


由于不需要A的返回值,因此无需等待任务在呼叫站点

Since the return value from A is not needed, there's no need to await the task at the call site

正确。


只要链中有人等待它(在C中发生),就无需在呼叫站点等待任务。

there's no need to await the task at the call site, as long as someone up the chain awaits it (which happens in C).



<现在你失去了我。为什么有人必须等待 A 返回的任务说出为什么您认为某人需要 来等待任务等待您可能有一个错误的信念。

Now you've lost me. Why does anyone have to await the Task returned by A? Say why you believe that someone is required to await that Task, because you might have a false belief.


我的同事非常执着,我开始怀疑自己。我的理解是错误的吗?

My coworker is very insistent and I began to doubt myself. Is my understanding wrong?

您的同事几乎肯定是错误的。您的分析似乎是正确的,直到您说有一个要求,每个 Task 等待 code> ed,这是不正确的。 奇怪不要 await 一个 Task ,因为这意味着您编写了一个程序,您开始了一项操作,并不在乎何时或如何完成操作,写这样的程序肯定闻起来很糟,但是<$>没有要求每个任务 c $ c> await 。如果您认为存在,请再说一遍,然后我们将对其进行整理。

Your coworker is almost certainly wrong. Your analysis seems correct right up to the bit where you say that there is a requirement that every Task be awaited, which is not true. It is strange to not await a Task because it means that you wrote a program where you started an operation and do not care about when or how it completes, and it certainly smells bad to write a program like that, but there is not a requirement to await every Task. If you believe that there is, again, say what that belief is and we'll sort it out.

这篇关于不等待异步调用仍然是异步的,对吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆