在控制台应用程序中使用.NET BackgroundWorker类

jvt*_*ech 12 .net multithreading backgroundworker

我对.NET编程和多线程一般都比较陌生,并且想知道是否可以使用.NET提供的BackgroundWorker来产生工作线程来在控制台应用程序中做一些工作?从在线的各种文档中,我看到这个类的意图更多的是面向UI的应用程序,你想在后台做一些工作,但保持UI响应,报告进度,取消处理,如果需要等.

在我的情况下,基本上我有一个控制器类,我想在多个工作线程中产生一些处理(限制使用信号量产生的最大工作线程数).然后我希望我的控制器类阻塞,直到所有线程都完成处理.所以在我启动一个工作线程做一些工作后,我希望线程能够在处理完成时通知控制器线程.我看到我可以使用后台工作者类,并处理事件DoWork和RunWorkerCompleted来实现这一点,但是想知道这是不是一个好主意?有没有更好的方法来实现这一目标?

Jon*_*eet 9

如果您的要求只是在所有线程完成之前阻塞,那就非常简单 - 只需启动新线程然后调用Thread.Join每个线程:

using System;
using System.Collections.Generic;
using System.Threading;

public class Test
{
    static void Main()
    {
        var threads = new List<Thread>();
        for (int i = 0; i < 10; i++)
        {
            int copy = i;
            Thread thread = new Thread(() => DoWork(copy));
            thread.Start();
            threads.Add(thread);
        }

        Console.WriteLine("Main thread blocking");
        foreach (Thread thread in threads)
        {
            thread.Join();
        }
        Console.WriteLine("Main thread finished");
    }

    static void DoWork(int thread)
    {
        Console.WriteLine("Thread {0} doing work", thread);
        Random rng = new Random(thread); // Seed with unique numbers
        Thread.Sleep(rng.Next(2000));
        Console.WriteLine("Thread {0} done", thread);
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:如果您可以访问.NET 4.0,那么TPL绝对是正确的方法.否则,我建议使用生产者/消费者队列(周围有大量的示例代码).基本上你有一个工作项队列,以及你拥有核心的许多消费者线程(假设它们是CPU限制的;你想要根据你的工作量来定制它).每个消费者线程都会从队列中获取项目并一次处理一个项目.你究竟如何管理这将取决于你的情况,但它并不是非常复杂.如果您能够提供开始时需要完成的所有工作,那就更容易了,这样线程可以在发现队列为空时退出.


Ree*_*sey 8

这在控制台应用程序中不起作用,因为永远不会初始化SynchronizationContext.Current.当您使用GUI应用程序时,这将由Windows窗体或WPF初始化.

话虽如此,没有理由这样做.只需使用ThreadPool.QueueUserWorkItem和一个重置事件(ManualResetEvent或AutoResetEvent)来捕获完成状态,并阻止你的主线程.


编辑:

在看到一些OP评论后,我想我会加上这个.

在我看来,"最好的"替代方案是获取Rx框架的副本,因为它包含.NET 4中TPL的后端.这将允许您使用Parallel.ForEach的重载,它提供了选项提供ParallelOptions实例.这将允许您限制并发操作的总数,并为您处理所有工作:

// using collection of work items, such as: List<Action<object>> workItems;
var options = new ParallelOptions();
options.MaxDegreeOfParallelism = 10; // Restrict to 10 threads, not recommended!

// Perform all actions in the list, in parallel
Parallel.ForEach(workItems, options, item => { item(null); });
Run Code Online (Sandbox Code Playgroud)

但是,使用Parallel.ForEach,我个人让系统管理并行度.它将自动分配适当数量的线程(特别是当/如果它移动到.NET 4).