【问题标题】:How to await for backgroundworker task complete before starting a new task in another backgroundworker?如何在另一个后台工作人员中开始新任务之前等待后台工作人员任务完成?
【发布时间】:2022-07-06 17:20:15
【问题描述】:

我最初的问题是关于 UI 阻塞,我有两个外部进程应该与其他一些代码连续执行,每个进程都会执行n times,这些进程的两个执行导致 UI 冻结, 为了避免这个问题,我在代码中实现了 backgroundworker 对象,第一个进程 ProcessA 将在 backgroundworker 中,第二个 ProcessB 将在 backgroundworker 中。

让我们从 ProcessA 开始,当我运行我的应用程序并开始执行整个任务时,ProcessA 会运行得如此之快并输出结果(我不知道为什么它运行得很快),对于结果,它们似乎是正确的。

ProcessA执行了n个步骤,每一步都会创建一个新的BackgroundWorker来做这个工作并在后台执行任务。

第二个进程必须在第一个进程完成后执行,我现在的问题是第一个进程的 CompletedTask 事件不会执行,第二个进程在第一个进程完成之前启动。

public void ButtonClick(object sender, RoutedEventArgs e)
{

    for (int i = 0; i < steps + 1; i++)
    {
        backgroundworker = new BackgroundWorker();
        backgroundworker.DoWork += new DoWorkEventHandler(BackgroundWorker_DoWork);
        backgroundworker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted;

        backgroundworker.RunWorkerAsync(Tuple.Create(mypath, i));
    }

    While(!FirstProcessFinished)
        Thread.Sleep(1000);

    RunSecondProcess(mypath);
}


protected void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
    // Some code to run first Process
}


protected void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    Counter++;
    IncrementProgressBar();
    Thread.Sleep();
    Console.WriteLine("Finished");
    if (counter == Steps + 1)
    {
        FirstProcessFinished = true;
    }
}

如何在调用 n 次 backgroundWorker_Completed 后正确执行 ProcessB

【问题讨论】:

标签: c# wpf multithreading backgroundworker


【解决方案1】:

来自docs

从 .NET Framework 4 开始,TPL 是编写多线程和并行代码的首选方式。

然后您可以实现类似这样的事件处理程序,以便在 FirstProcess 完成后立即执行 SecondProcess

public void ButtonClick(object sender, RoutedEventArgs e)
{
    Task.Run(FirstProcess)
        .ContinueWith(_ => SecondProcess);
}

private void FirstProcess()
{

}

private void SecondProcess()
{

}

或者使用 .NET Framework 4.5 中引入的 asyncawait 关键字:

public void ButtonClick(object sender, RoutedEventArgs e)
{
    await Task.Run(FirstProcess);
    await Task.Run(SecondProcess);
}

BackgroundWorker 或多或少已成为过去。

【讨论】:

    【解决方案2】:

    Taskasyncawait 是要走的路。 这是您可以编写的示例:

    public void ButtonClick(object sender, RoutedEventArgs e)
    {
        Work();
    }
    
    
    // async void should be used with caution.
    // see: https://johnthiriet.com/mvvm-going-async-with-async-command/
    private async void Work()
    {
        try
        {
            // start all A tasks
            var aTasks = Enumerable.Range(0, steps + 1).Select(i => RunA(myPath, i));
    
            // wait for them to end
            await Task.WhenAll(aTasks);
    
            // start B task (it will not be allowed to update the UI)
            await Task.Run(() => RunB(myPath));
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
            throw;
        }
    }
    
    private async Task RunA(string path, int index)
    {
        // start the actual work (new task to not freeze the UI)
        await Task.Run(() => WorkA(path, index));
    
        // here we are back on the UI thread so we can update the status
        IncrementProgressBar();
    
        Console.WriteLine($"Task A{index:00} Finished");
    }
    
    private void WorkA(string path, int index)
    {
        // the work
    }
    
    private void RunB(string path)
    {
        // the work
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-06
      • 1970-01-01
      • 1970-01-01
      • 2011-01-29
      相关资源
      最近更新 更多