【问题标题】:Backgroundworker is always busy后台工作人员总是很忙
【发布时间】:2015-06-12 22:14:45
【问题描述】:

我不熟悉使用事件处理程序和后台工作程序,所以我可能在这里遗漏了一些非常明显的东西。尽管如此,我已经尝试解决这个问题两天了,所以我想我不妨看看有人要说什么。

我有一个名为 SqlExpressDownloader 的后台工作人员。它在我的程序开始时开始运行,其余的工作运行,然后它应该等待SqlExpressDownloader_DoWork() 方法中的操作完成后再继续。唯一的问题是,出于某种原因,每当我执行while(SqlExpressDownloader.IsBusy) 时,它总是响应忙,因此将永远等待。

事件处理程序的代码在这里:

    private void SqlExpressDownloader_DoWork(object sender, DoWorkEventArgs e)
    {
        string sSource = string.Format("{0}\\{1}", Paths.Settings_Common, "sqlexpr_x64_enu.exe");
        Debug.WriteLine(sSource);
        Debug.WriteLine("http://www.elexioamp.com/Install/redistributables/sql2008r2express/sqlexpr_x64_enu.exe");
        if (!System.IO.File.Exists(sSource))
        {
            WebClient oWebClient = new WebClient();
            oWebClient.DownloadProgressChanged += DownloadProgressChanged;
            oWebClient.DownloadDataCompleted += DownloadComplete;

            oWebClient.DownloadFileAsync(new System.Uri("http://www.elexioamp.com/Install/redistributables/sql2008r2express/sqlexpr_x64_enu.exe"), sSource);

            while (oWebClient.IsBusy)
            {
                Thread.Sleep(100);
            }

            e.Result = "";
            DownloadFinished = true;
        }
    }

我已经看过代码并且已经看过它完成了这个方法。我什至在DownloadFinished = true 之后添加了return,但它仍然响应为忙。我想知道的是如何让后台工作人员响应不忙。

编辑 事件都添加到构造函数中,如下所示:

        SqlExpressDownloader = new BackgroundWorker();
        SqlExpressDownloader.DoWork += new DoWorkEventHandler(this.SqlExpressDownloader_DoWork);
        SqlExpressDownloader.RunWorkerCompleted += new RunWorkerCompletedEventHandler(this.SqlExpressDownloader_RunWorkerCompleted);

RunWorkerCompleteEventHandler 看起来像这样:

    private void SqlExpressDownloader_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if (e.Error != null)
        {
            Debug.WriteLine("The actions are complete.");
        }
        else
        {
            Debug.WriteLine("Error in completed work.");
        }
    }

但是,当我上次调试它时,它实际上并没有触发。

【问题讨论】:

  • 你是如何启动worker的?
  • 在main方法中,我以SqlExpressDownloader.RunWorkerAsync()开头。
  • 在检查工作人员的 IsBusy 时,您是否使用了类似于方法主体中的 while 循环?方法完成时是否触发 RunWorkerCompleted 事件?
  • while 循环看起来和这里列出的几乎一模一样。我在问题中更新了有关 RunWorkerCompleted 的信息。
  • 是否有一些其他代码可以将处理程序添加到 DoWork 事件,可能在 .designer.cs 文件中?您的代码应该按照您的方式工作。

标签: c# event-handling backgroundworker


【解决方案1】:

不要在循环中查询SqlExpressDownloader.IsBusy,而是尝试订阅BackgroundWorkerRunWorkerCompleted 事件并将您的代码放入其中,该代码仅应在DoWork 事件完成后发生。

您还可以访问RunWorkerCompletedEventArgs,您可以检查它以确保您的BackgroundWorkerDoWork 部分没有引发错误。

    ...
    ...
    SqlExpressDownloader.RunWorkerCompleted += SqlExpressDownloader_RunWorkerCompleted;
    SqlExpressDownloader.RunWorkerAsync();
}

private void SqlExpressDownloader_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Error != null)
    {
        // do something in response to the error
    }

    // stuff to do after DoWork has completed
}

我发现Joe Albahari's tutorial 在我学习如何使用它们时很有帮助。

【讨论】:

    【解决方案2】:

    你可以用更优雅的异步/等待解决方案替换你的代码

    private async Task SqlExpressDownloadAsync()
    {
        string sSource = string.Format("{0}\\{1}", Paths.Settings_Common, "sqlexpr_x64_enu.exe");
        Debug.WriteLine(sSource);
        Debug.WriteLine("http://www.elexioamp.com/Install/redistributables/sql2008r2express/sqlexpr_x64_enu.exe");
        if (!System.IO.File.Exists(sSource))
        {
            WebClient oWebClient = new WebClient();
            oWebClient.DownloadProgressChanged += DownloadProgressChanged;
            oWebClient.DownloadDataCompleted += DownloadComplete;
            await oWebClient.DownloadFileTaskAsync(new System.Uri("http://www.elexioamp.com/Install/redistributables/sql2008r2express/sqlexpr_x64_enu.exe"), sSource);  
        }   
    }
    

    【讨论】:

    • 我对任务不熟悉。我是否能够像在后台工作程序上使用事件处理程序一样跟踪下载进度?我的项目中涉及一个 GUI 组件。我会试试这个。
    • 虽然目前这不是异步运行的。你应该把它包装在一个 task.run
    • 绝对!我添加了缺少的事件句柄,它们会像你的代码一样触发。
    • @Patrick 你能详细说明一下吗?代码等待 DownloadFileTaskAsync
    • @Patrick 好问题,你认为它会运行多久?也请提供您的答案。
    【解决方案3】:

    我遇到了类似的问题。 DownloadASync 会触发,但 .IsBusy 将始终保持为真。

    这可能不是一个常见的问题,只是想我分享我的解决方案。

    我用过

    MessageBox.Show(new Form() { TopMost = true }, "", "")
    

    这就是原因。我也试过了:

    var t = new Form() { TopMost = true };
    MessageBox.Show(t, "", "");
    t.Dispose();
    

    这导致了同样的问题。

    我的代码有多个线程,我假设其中一个一定是卡住了,或者 MessageBox(the new Form() { TopMost = true; } ) 调用创建了一个卡住的线程。

    只要我删除了那部分,例如。

    MessageBox.Show("", "");
    

    一切都再次按预期工作。

    因此,也许您正在某个地方创建另一个导致您的问题的线程。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-14
      • 1970-01-01
      • 1970-01-01
      • 2015-12-07
      • 1970-01-01
      相关资源
      最近更新 更多