Multithreading 对TPL使用async/await会干扰BackgroundWorker吗?

Multithreading 对TPL使用async/await会干扰BackgroundWorker吗?,multithreading,winforms,task-parallel-library,backgroundworker,async-await,Multithreading,Winforms,Task Parallel Library,Backgroundworker,Async Await,我有一个遗留的(有几年历史的)WinForms项目,目前在.NET4.0中。目前大多数的数据检索都使用了后台工作人员>代码>类/模式进行异步检索,但我正在添加一些新的功能,并希望使用异步代码>代码>。该方法在开发和测试环境中运行良好,但我们的一些用户(相当多)在程序中出现了错误,这些错误似乎与线程有关;具体来说,如果您使用的不是UI线程,而是修改UI绑定数据,那么您可能会看到什么 其中一个遗留控件的示例如下: public class LegacyControl { public voi

我有一个遗留的(有几年历史的)WinForms项目,目前在.NET4.0中。目前大多数的数据检索都使用了<代码>后台工作人员>代码>类/模式进行异步检索,但我正在添加一些新的功能,并希望使用<代码>异步代码>代码>。该方法在开发和测试环境中运行良好,但我们的一些用户(相当多)在程序中出现了错误,这些错误似乎与线程有关;具体来说,如果您使用的不是UI线程,而是修改UI绑定数据,那么您可能会看到什么

其中一个遗留控件的示例如下:

public class LegacyControl
{
    public void LoadData(int id)
    {
        while(isLoading)
        {
            Application.DoEvents();
            Thread.Sleep(50);
        }

        isLoading = true;

        currentId = id;

        worker.RunWorkerAsync(id);
    }

    private bool isLoading;
    private int currentId;
    private object myData;

    private void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        myData = RetrieveData(currentId);
    }

    private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        bindingSource.DataSource = myData;
    }
}
public class NewControl
{
    public void LoadData(int id)
    {
        LoadDataAsync(id).ContinueWithErrorHandling(); // custom extension method to generically handle unhandled task exceptions.
    }

    private async Task LoadDataAsync(int id)
    {
        var data = await RetrieveSomeOtherDataAsync(id);

        bindingSource.DataSource = data;
    }
}
其中一种新控制措施的示例如下:

public class LegacyControl
{
    public void LoadData(int id)
    {
        while(isLoading)
        {
            Application.DoEvents();
            Thread.Sleep(50);
        }

        isLoading = true;

        currentId = id;

        worker.RunWorkerAsync(id);
    }

    private bool isLoading;
    private int currentId;
    private object myData;

    private void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        myData = RetrieveData(currentId);
    }

    private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        bindingSource.DataSource = myData;
    }
}
public class NewControl
{
    public void LoadData(int id)
    {
        LoadDataAsync(id).ContinueWithErrorHandling(); // custom extension method to generically handle unhandled task exceptions.
    }

    private async Task LoadDataAsync(int id)
    {
        var data = await RetrieveSomeOtherDataAsync(id);

        bindingSource.DataSource = data;
    }
}
虽然我对这种可能性持怀疑态度,但我正在竭尽全力想弄清楚这里到底发生了什么。是否有可能使用
async
/
await
以某种方式破坏了
BackgroundWorker
,并导致其
RunWorkerCompleted
事件在后台线程而不是UI线程上运行


我可以尝试删除TPL代码,但由于我无法在我的环境中重现错误行为,我实际上没有任何测试方法。

async
根本不会影响
BackgroundWorker
BackgroundWorker
是它自己的完全独立的线程


您发布的代码中最可疑的部分是
DoEvents
。这将创建一个嵌套的消息循环,因此您必须考虑整个应用程序,并确保您拥有的任何UI事件处理程序(以及
async
continuation)在从该方法调用时都能正常工作。

async
根本不会干扰
BackgroundWorker
BackgroundWorker
是它自己的完全独立的线程


您发布的代码中最可疑的部分是
DoEvents
。这会创建一个嵌套的消息循环,因此您必须考虑整个应用程序,并确保您拥有的任何UI事件处理程序(以及
async
continuation)在从该方法调用时都能正常工作。

我同意,但这个问题恰恰是在首次使用
async
/
await
时出现的,这一事实很难忽视。虽然我同意应该避免使用
DoEvents
,而且我自己也不使用它,但这些组件已经以这种方式存在了好几年。可重入性bug非常常见,
DoEvents
将根据一百种其他因素(如机器负载、第三方应用程序、CPU电源、,几乎所有影响代码精确计时的事情。因此,这可能是由于添加了
async
组件时出现了一些模糊的时间安排,这些时间安排稍有不同,但我的关注点是
DoEvents
中的核心问题。我同意,但这个问题恰恰是在首次使用
async
/
wait
时出现的,这一事实很难忽视。虽然我同意应该避免使用
DoEvents
,而且我自己也不使用它,但这些组件已经以这种方式存在了好几年。可重入性bug非常常见,
DoEvents
将根据一百种其他因素(如机器负载、第三方应用程序、CPU电源、,几乎所有影响代码精确计时的事情。因此,这可能是由于添加了
async
组件时出现了一些模糊的时间安排,这些时间安排略有不同,但我的重点是
DoEvents
中的核心问题。