【问题标题】:Can using async/await with the TPL interfere with the BackgroundWorker?在 TPL 中使用 async/await 会干扰 BackgroundWorker 吗?
【发布时间】:2013-10-11 10:41:55
【问题描述】:

我有一个遗留的(几年前的)WinForms 项目,目前在 .NET 4.0 中。当前的大多数数据检索使用BackgroundWorker 类/模式进行异步检索,但我正在添加一些新功能并希望使用async 模式(通过Async Targeting Pack)。该方法在开发和测试环境中运行良好,但我们的一些(非平凡数字)用户在程序中遇到了似乎与线程相关的错误;具体来说,如果您有除 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;
    }
}

虽然我对这种可能性持怀疑态度,但我正在努力弄清楚这里发生了什么。是否有可能使用async/await 会以某种方式弄乱BackgroundWorker 并导致其RunWorkerCompleted 事件在后台线程而不是UI 线程上运行?

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

【问题讨论】:

    标签: multithreading winforms task-parallel-library backgroundworker async-await


    【解决方案1】:

    async 根本不会与BackgroundWorker 混淆。 BackgroundWorker 是它自己完全独立的线程。

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

    【讨论】:

    • 我同意,但这个问题恰好在首次使用async/await 时出现,这一事实难以忽视。虽然我同意应该避免使用DoEvents,而且我自己也不使用它,但这些组件已经以这种方式存在了好几年。
    • 重入错误非常普遍,DoEvents 将根据其他一百个因素(例如机器负载、第三方应用程序、CPU 能力以及几乎任何影响精确计时的因素)显示这些错误的代码。因此,这可能是由于添加async 组件时一些模糊的时间略有不同造成的,但我的钱是在DoEvents 中的核心问题。
    猜你喜欢
    • 1970-01-01
    • 2016-05-24
    • 2017-05-23
    • 2012-08-08
    • 1970-01-01
    • 1970-01-01
    • 2017-12-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多