1

我在使用 BackgroundWorker 时发现了一个问题。发生的情况是 BackgroundWorker 进程可以正常工作,然后偶尔需要大约 40-50 秒才能开始。

该问题出现在两台机器上。BackgroundWorker 操作一整天都运行良好,然后在下午开始出现此问题,该过程需要 40 秒而不是 1 秒,但只是偶尔发生。你可以做好其中的 5 个,而第 6 个则需要 40 秒。然后你可以再做 5 次罚款。如果它确实开始花费超过一秒的时间,您可以在 workingDialog 上按取消并立即再次执行,它会起作用。在进一步检查中,工人似乎没有立即启动 DoWork 方法。

我可能会用完线程或其他东西吗?或者我如何处理 BackgroundWorker 可能存在问题?代码如下;

using (workingDialog = new Dialogs.WaitDialog()) {
    StartThreadedWork(MyDoWorkMethod, customerID);

    // if user presses cancel button
    if (workingDialog.ShowDialog() == System.Windows.Forms.DialogResult.Cancel) {
        m_Worker.RunWorkerCompleted -= ThreadFinished;
    }
}
m_Worker.Dispose();
m_Worker = null;

'StartThreadedWork' 方法如下;

private void StartThreadedWork(DoWorkEventHandler method, int customerID) {
    m_Worker = new BackgroundWorker();
    m_Worker.DoWork += method;
    m_Worker.RunWorkerCompleted += ThreadFinished;
    object[] parameters = new object [] {customerID };
    m_Worker.RunWorkerAsync(parameters);
}

最后,分配给 DoWork 事件处理程序的方法是:

private void ThreadSyncing(object sender, DoWorkEventArgs e) {
    object[] parameters = e.Argument as object[];
    int customerID = (int)parameters[0];
    Customer resultCustomer = new Customer(FormsManager.Instance.BillingWebService.Customer_GetByCustomerID(customerID, CustomerSyncOption.Default));
    e.Result = resultCustomer;
}

触发 RunWorkerCompleted 事件后,对话框结果将设置为 OK 并关闭对话框。

对此的任何指示将不胜感激!

谢谢,

4

2 回答 2

2

你怎么知道实际上是 BGW 的启动延迟了?您没有提供任何反馈,您所看到的只是它已完成。看起来您正在使用 Web 服务,服务器没有响应或完成请求,持续 40 秒并不异常。默认的 tcp/ip 连接超时为 45 秒。

ThreadPool 调度器可以发挥作用,它试图将执行 TP 线程的数量限制为机器拥有的 cpu 核心数。然而,获得 40 秒的延迟是一个沉重的角落案例。如果现有线程未完成,调度程序允许另一个 TP 线程启动,每秒两次。因此,您必须有 80 个活动 TP 线程才能产生这样的延迟。

关于您使用的对话框值得注意的一件事是,它实际上并没有做任何事情来停止工作线程。它只是放弃它。因此,如果服务器没有响应并且用户不耐烦,您可能会积聚起来。在她的脚轻敲四次后反复按取消按钮。这确实会导致不断增加的延误。您应该使用 CancelAsync() 方法并使用 CancellationPending 属性实现取消逻辑。但是,是的,使用 Web 服务通常不容易做到这一点。

通过提供更好的反馈来解决这个问题。当用户取消时,不要取消订阅 RunWorkerCompleted 事件。只需设置一个标志,指示最后一个请求已被取消。在您的 UI 中显示 Web 服务在工作人员完成之前不可用。包括不允许用户再次启动Web服务请求。

于 2012-09-09T21:26:00.563 回答
1

BackgroundWorker 使用 .Net 线程池执行其 DoWork 方法。

如果你在线程池上施加了过多的负载,一些工作项将被延迟,直到它有一个可用的线程来处理它们。

于 2012-09-09T16:57:47.740 回答