简体   繁体   English

C#backgroundworker RunworkerCompleted vs async await

[英]C# backgroundworker RunworkerCompleted vs async await

Updated with answers: The true way of wait until a number of different tasks to be finished would need async await instead of background worker. 更新了答案:等待完成许多不同任务的真正方式需要异步等待而不是后台工作者。

#

I know there are numerous discussion about backgroundworker but I've being searched around and cannot find the answer. 我知道有很多关于背景工作者的讨论,但我一直在搜索,找不到答案。

Here is my code example(basic logic, the actual code is much longer), I wonder if there is a way to get around this: 这是我的代码示例(基本逻辑,实际代码要长得多),我想知道是否有办法解决这个问题:

void MCIATS1Worker_DoWork(object sender, DoWorkEventArgs e)
    {
        //do something here
    }

    void MCIATS1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        MessageBox.Show("hello world");
        _MCIATS1WorkerResetEvent.Set();
    }

DoWork and runworkercompleted DoWork和runworker完成了

 void MCIATS1Worker_DoWork(object sender, DoWorkEventArgs e) { //do something here } void MCIATS1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { MessageBox.Show("hello world"); _MCIATS1WorkerResetEvent.Set(); } 

For some reasons, the MCIATS1_RunWorkerCompleted won't be triggered until the loop finished. 由于某些原因,在循环结束之前不会触发MCIATS1_RunWorkerCompleted。 And apparently the WaitOne is holding the loop. 显然,WaitOne正在保持循环。
Here is my question, 这是我的问题,

why RunWorkerCompleted won't be trigger the RunWorkerCompleted when the worker is actually finished the work? 当工作人员实际完成工作时,为什么RunWorkerCompleted不会触发RunWorkerCompleted?

Thank you. 谢谢。

###UPDATED SOLUTION ###更新的解决方案

This is the right way of doing it. 这是正确的做法。

 private async void WhateverFunction() { await Task.WhenAll(MCIATS1WorkerDoWorkAsync(param),...other tasks); } private Task MCIATS1WorkerDoWorkAsync(bkgWorkParameter param) { return Task.Run(() => { //Do whatever }); } 

It happens because when you use a BackgroundWorker it's RunWorkerCompleted event is posted to the SynchronizationContext of the thread that called RunWorkerAsync . 这是因为当您使用BackgroundWorker它的RunWorkerCompleted事件被发布到调用RunWorkerAsync的线程的SynchronizationContext

Because you call RunWorkerAsync on the UI thread the event can't run until the UI thread starts processing new messages in the message loop. 因为您在UI线程上调用RunWorkerAsync ,所以在UI线程开始处理消息循环中的新消息之前,事件无法运行。 However you prevented the UI thread from returning to the message loop by your _MCIATS1WorkerResetEvent.WaitOne(); 但是,您阻止了UI线程通过_MCIATS1WorkerResetEvent.WaitOne();返回到消息循环_MCIATS1WorkerResetEvent.WaitOne(); call. 呼叫。

So what it boils down to is _MCIATS1WorkerResetEvent.Set(); 所以归结为_MCIATS1WorkerResetEvent.Set(); is waiting for MCIATS1_RunWorkerCompleted to fire to stop blocking and MCIATS1_RunWorkerCompleted is waiting for _MCIATS1WorkerResetEvent.Set(); 等待MCIATS1_RunWorkerCompleted触发停止阻塞, MCIATS1_RunWorkerCompleted正在等待_MCIATS1WorkerResetEvent.Set(); to stop blocking the UI thread so it's message to be processed. 停止阻止UI线程,以便处理它的消息。

Both things are waiting for the other to complete before itself completes and you have a classic deadlock. 在事情完成之前,两件事都在等待对方完成,你有一个经典的死锁。

There is no need for a for loop for this problem to happen, this same problem would happen with or without out the loop, in fact the loop never gets to run it's 2nd itteration because it will have deadlocked on the first time through so it does not matter that there is a loop at all. 没有必要为一个for循环对于这个问题发生,同样的问题就会有或没有跳出循环发生,实际上循环永远不会获取运行它的第2个itteration,因为它会在第一时间僵持通过它确实是这样无论有什么循环都没关系。

Depend on what kind of work your MCIATS1Worker_DoWork method do, you can consider to use async-await approach, which makes code a little bid more cleaner. 根据您的MCIATS1Worker_DoWork方法所做的工作,您可以考虑使用async-await方法,这会使代码更加清晰。

private async Task MCIATS1WorkerDoWorkAsync()
{        
    await Task.Delay(1000) // do something asynchronously for 1 second
}

private async void MainWindow_Load(object sender, EventArgs e)
{
     for (int i = 1; i <= 10; i++)
     {
        //some code
        await MCIATS1WorkerDoWorkAsync();
        MessageBox.Show("hello world");
     }       
}

Message box will be shown 10 times every 1 second. 消息框每1秒显示10次。 await keyword will continue loop only after MCIATS1WorkerDoWorkAsync method has successfully finished. 只有在MCIATS1WorkerDoWorkAsync方法成功完成后, await关键字才会继续循环。

With async-await your form will remain responsive and if DoWork method do some IO operations, then you will not start another thread (as BackgroundWorker do) and whole execution will happens on one thread. 使用async-await您的表单将保持响应,如果DoWork方法执行某些IO操作,那么您将不会启动另一个线程(如BackgroundWorker那样)并且整个执行将在一个线程上发生。

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

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