简体   繁体   English

等待任务vs等待Task.Run(voidMethod)

[英]await Task vs await Task.Run(voidMethod)

I'm confused why the output of these 2 programs differs: 我很困惑为什么这两个程序的输出不同:

private async void button1_Click(object sender, EventArgs e)
{
    for (int i = 0; i < 33; i++)
    {
        await LongProcess();
    }
}

private async Task LongProcess()
{
    await Task.Delay(1000);
    progressBar1.Value += 3;
}

and

private async void button1_Click(object sender, EventArgs e)
{
    for (int i = 0; i < 33; i++)
    {
        await Task.Run(() => LongProcess());
    }
}

private async void LongProcess()
{
    await Task.Delay(1000);
    progressBar1.Value += 3;
}

I realize the first example returning Task is more correct, but I don't understand why wrapping the void function in a Task.Run doesn't produce the same output? 我意识到返回Task的第一个示例更正确,但是我不明白为什么将void函数包装在Task.Run中不会产生相同的输出? The first function does what I expect, updates the progress bar every 1 second. 第一个功能完成了我所期望的,每1秒钟更新进度条。 The second code attempts to update the progress bar all at once, causing problems attempting to update the same UI element from multiple threads. 第二个代码尝试一次全部更新进度条,从而导致尝试从多个线程更新同一UI元素时出现问题。

My assumption was since the buttonClick method awaits the long process to complete, both sets of code should not allow the progressBar1 update to happen until the previous process has completed. 我的假设是,因为buttonClick方法等待较长的过程完成,所以在上一个过程完成之前,两组代码都不应允许progressBar1更新。 Why does the second set of code allow it to happen all at once? 为什么第二组代码允许它一次全部发生?

This isn't doing what you think it is: 这不是您想的那样:

await Task.Run(() => LongProcess());

The code is awaiting Task.Run() , but nothing within that task is awaiting LongProcess() . 该代码正在等待Task.Run()但该任务没有任何正在等待LongProcess() So Task.Run() returns immediately in this case. 因此,在这种情况下Task.Run()立即返回。

This is actually an interesting illustration of a failure to be "async all the way down", because the inline function is essentially hiding the fact that it's async. 这实际上是一个有趣的例子,说明失败是“一直向下同步”的原因,因为内联函数本质上隐藏了异步的事实。 And in fact the compiler should be warning you that nothing is awaiting LongProcess() and that it would return immediately. 实际上,编译器应该警告您没有任何东西正在等待LongProcess() ,并且它将立即返回。

Contrast it with this: 与此相反:

await Task.Run(async () => await LongProcess());

Edit: I just noticed why the compiler probably isn't warning you. 编辑:我只是注意到为什么编译器可能没有警告您。 Because of this: 因为这:

async void

Never, ever, ever do this :) (Well, ok, there's one valid reason to do this. And I'm sure it haunts the C# team to this day that they had to support it just for that one reason. But unless you encounter that one reason, don't do it.) 永远不要,永远不要这样做:)(好吧,这样做有一个正当的理由。我敢肯定,直到今天,C#团队仍在困扰他们,因为这个原因他们不得不支持它。但是除非您遇到一个原因,请不要这样做。)

Always return a Task for async methods so that the method can be awaited. 始终为异步方法返回Task ,以便可以等待该方法。

In the first program, LongProcess returns a Task , and Task.Run is wrapping it -- basically just launching it in the default scheduler rather than whatever context you're currently on. 在第一个程序中,LongProcess返回一个Task ,而Task.Run包装它-基本上只是在默认的调度程序中启动它,而不是当前所处的上下文。

You'll notice that Task.Run has overloads specifically to do this wrapping, and is not returning a Task<Task> . 您会注意到Task.Run有专门用于此包装的重载,并且没有返回Task<Task>

In the second program, LongProcess is an async void method, which means Task.Run has nothing to wrap and will complete more or less immediately, and before the work is guaranteed to be done. 在第二个程序中,LongProcess是一个async void方法,这意味着Task.Run没有要包装的东西,它将在保证完成工作之前立即或多或少地完成。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM