【问题标题】:C# should I create one Background worker or many?C# 我应该创建一个后台工作者还是多个?
【发布时间】:2011-09-13 18:48:00
【问题描述】:

我是那些偶然的程序员之一,所以我没有太多关于编程最佳实践的知识。

我有一个当前使用 4 个后台工作器的应用程序。

所以我声明它们:

private BackgroundWorker bw1;
private BackgroundWorker bw2;
private BackgroundWorker bw3;
private BackgroundWorker bw4;

然后配置它们:

bw1 = new BackgroundWorker();
bw1.WorkerReportsProgress = true;
bw1.DoWork += new DoWorkEventHandler(bw1_DoWork);
bw1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw1_RunWorkerCompleted);
bw1.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);

bw2 = new BackgroundWorker();
bw2.WorkerReportsProgress = true;
bw2.DoWork += new DoWorkEventHandler(bw2_DoWork);
bw2.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw2_RunWorkerCompleted);
bw2.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);

bw3 = new BackgroundWorker();
bw3.WorkerReportsProgress = true;
bw3.DoWork += new DoWorkEventHandler(bw3_DoWork);
bw3.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw3_RunWorkerCompleted);
bw3.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);

bw4 = new BackgroundWorker();
bw4.WorkerReportsProgress = true;
bw4.DoWork += new DoWorkEventHandler(bw4_DoWork);
bw4.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw4_RunWorkerCompleted);
bw4.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);

然后我使用 bw1.RunWorkerAsync()、bw2.RunWorkerAsync() 等等...

问题是我从不同时调用它们,它们以非常线性的方式在不同点调用。

所以我的问题是,是拥有许多“预配置”后台工作人员更好还是拥有一个并根据我想要的方式更改 DoWork 和 RunWorkerCompleted 事件?

【问题讨论】:

  • 如果您确实使用多个后台工作人员,您应该将它们放在List<BackgroundWorker> 中以防止冗余代码。那样的话,再多加十个,就不用加十倍的代码量了。
  • @DevinBurke:我不确定backgroundWorkers[4] 之类的内容是否比updateOrdersBackgroundWorker 之类的内容更具描述性。这里的字段可能是带有名称的示例,但至少字段允许您为您拥有的东西命名。

标签: c# backgroundworker


【解决方案1】:

通常我以完全不同的模式使用后台工作人员。我不是在开始时一次性定义它们,包括它们各自的事件处理程序,而是在我做一些需要它们的事情时动态创建它们。

public void SomeEventHandlerMaybe(object sender, EventArgs e) {
  // do something

  var bw = new BackgroundWorker();
  bw.ReportsProgress = true;
  bw.DoWork += delegate {
    // do work. You can use locals from here
  };
  bw.ProgressChanged += delegate { ... };
  bw.RunWorkerCompleted += delegate {
    // do something with the results.
  };
  bw.RunWorkerAsync();
}

类似的东西。这样做的好处是,您可以将所有代码与后台工作人员一起或在后台工作人员中执行某些操作,并且大致按正确的顺序。

【讨论】:

  • 我没想过即时创建它们,这对我来说是个好途径,谢谢!
  • 这种方法是否允许您在 DoWork 中 ReportProgress(i) 并在 ProgressChanged 委托中获取 ProgressPercent?
  • 我自己的问题的答案是肯定的..bw.ProgressChanged += delegate(object sender, ProgressChangedEventArgs e)
【解决方案2】:

从架构的角度来看,每个后台任务最好有一个单独的后台工作者,这在逻辑上与类的其他任务无关。

【讨论】:

  • 在我看来更多的是资源分配。您应该按任务将后台工作人员组合在一起,但任何任务都可能有多个。例如,在大多数情况下,读取只有一个威胁的文件系统比拥有 5 个威胁要慢得多。但是,如果您正在读取USB闪存驱动器,则在通过2-3之后通常会变慢,因此200是浪费。我有一个“读取硬盘驱动器”、“读取 SSD”、“读取闪存驱动器”组,每个组都有一个适当的数字。无论如何,假设我想同时阅读所有三个。
【解决方案3】:

一般来说,使用多线程是合理的,如果它有助于更​​有效地使用您的系统上的资源。对于 CPU 密集型任务,每个 CPU 内核一个线程是一个很好的起点。对于 IO 密集型任务,您当然可以拥有更多。

如果您可以灵活地使用 .NET 4,我会考虑使用 Task Parallel Library 而不是 BackgroundWorker。默认情况下,除了提供更简单的编程模型外,它还会为您做出关于并发运行多少线程的相对明智的决定。

【讨论】:

  • 我会看看 TPL,我使用的是 .NET 4。
  • 谢谢,以后我也会尝试理解TPL。
【解决方案4】:

使用 BackgroundWorker 进行处理意味着您在单独的线程中进行处理。因此,如果您不需要多线程,则不需要单独的后台工作人员。如果您在启动每个工作人员后等待完成,则您可以只有一名工作人员。它也可能会删除一些代码重复...

【讨论】:

    【解决方案5】:

    您出于某种计算目的运行工作程序。如果一个调用的计算被使用或以任何方式依赖于另一个调用,您可以使用多个工作人员,以获得更好的性能(顺便说一下,这也是一个衡量的主题)。如果您只需要完成 4 个工作,并在单独的线程中运行它们只是为了不阻塞主 UI,那么一个工作人员是很好的解决方案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-18
      • 2011-03-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多