【问题标题】:Many short tasks on the guigui上的许多简短任务
【发布时间】:2012-08-10 11:10:49
【问题描述】:

当我必须执行许多与 GUI 合作的短任务时,我应该为每个任务使用另一个 BackgroundWorker,还是使用其他解决方案?

编辑

我的意思是每 5 秒更新一次 datagridview 中的每个单元格(200 行 x 50 列)。每个单元格都存储图像。

【问题讨论】:

  • 一两个你想到的任务的例子会有很大帮助。
  • 我们所说的“短”有多“短”?如果您不希望 UI 在任务运行时冻结,显然您应该使用另一个线程。 BackgroundWorker 使您可以轻松地在另一个线程中运行您的任务,并在任务完成后通知您并提供进度信息。

标签: c# multithreading user-interface .net-4.0 backgroundworker


【解决方案1】:

BackgroundWorker 更适合长时间运行的任务,您需要类似ThreadPool 的东西。这是一个非常粗略的例子:

QueueUserWorkItem 允许您指定一个工作方法并传入一个对象以供该方法使用。

ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork), object);

然后你就会有你的 DoWork 方法,所有的魔法都会发生:

public void DoWork(object sender)
{
     object s = (object)sender;

     this.Invoke(new ThreadDone(ReportProgress), result);
}

注意对this.Invoke(new TaskDone(ReportProgress)); 的调用,这会安全地调用在主线程上运行的代码,以使用来自DoWork 的已处理数据更新您的UI。这是通过私人委托完成的:

private delegate void ThreadDone(object yourObject);

会调用:

private void ReportProgress(object yourObject)
{
       //update UI
}

您还可以通过跟踪 Interlocked 计数器对象来检查任务何时完成,例如

foreach (string s in strings)
{
      ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork), s);
      Interlocked.Increment(ref workItems);
}

然后在单个线程完成时递减workItems,并简单检查何时workItems == 0

Interlocked.Decrement(ref workItems);

if (workItems == 0)
{
       this.Invoke(new TaskDone(WorkComplete));
}

希望这会有所帮助。

【讨论】:

    【解决方案2】:

    当我处理许多小任务时,我倾向于发现ThreadPool 是处理它们的好方法。您可以像这样在后台线程上分派委托:

    ThreadPool.QueueUserWorkItem(new WaitCallback(MyThreadProc));
    

    您也可以将对象作为状态传递给线程,考虑一个将对象作为参数的委托。你可以这样称呼:

    ThreadPool.QueueUserWorkItem(new WaitCallback(MyThreadProc), state);
    

    state 是您的线程知道如何处理的某个对象。

    编辑ThreadPool 方法应该适用于您的场景。只需确保必须在 GUI 线程上调用任何更改您的 GUI 的代码,否则您会遇到一些跨线程异常。

    【讨论】:

      猜你喜欢
      • 2019-01-13
      • 2012-10-24
      • 2022-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-20
      • 2017-08-10
      • 1970-01-01
      相关资源
      最近更新 更多