为工作生成多个线程,然后等到所有完成

pha*_*roc 53 c# multithreading backgroundworker

只想就多线程任务的"最佳实践"提出一些建议.

例如,我们有一个C#应用程序,它在启动时从我们数据库中的各种"类型"表中读取数据,并将信息存储在我们传递给应用程序的集合中.这可以防止我们每次需要此信息时都会访问数据库.

此时应用程序正在同步读取10个表中的数据.我真的希望从一个并行运行的不同线程中的每个表中读取应用程序.在继续启动应用程序之前,应用程序将等待所有线程完成.

我已经研究过BackGroundWorker但只是想要一些关于完成上述工作的建议.

  1. 该方法是否合乎逻辑,以加快应用程序的启动时间
  2. 我们如何才能最好地处理所有线程,记住每个线程的工作是彼此独立的,我们只需要等待所有线程完成后再继续.

我期待着一些答案

Ree*_*sey 91

我对此的偏好是通过单个WaitHandle来处理这个问题,并使用Interlocked来避免锁定计数器:

class Program
{
    static void Main(string[] args)
    {
        int numThreads = 10;
        ManualResetEvent resetEvent = new ManualResetEvent(false);
        int toProcess = numThreads;

        // Start workers.
        for (int i = 0; i < numThreads; i++)
        {
            new Thread(delegate()
            {
                Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
                // If we're the last thread, signal
                if (Interlocked.Decrement(ref toProcess) == 0)
                    resetEvent.Set();
            }).Start();
        }

        // Wait for workers.
        resetEvent.WaitOne();
        Console.WriteLine("Finished.");
    }
}
Run Code Online (Sandbox Code Playgroud)

这很好用,可以扩展到任意数量的线程处理,而不会引入锁定.


Jac*_*tch 28

我喜欢@Reed的解决方案.在.NET 4.0中实现相同功能的另一种方法是使用CountdownEvent.

class Program
{
    static void Main(string[] args)
    {
        var numThreads = 10;
        var countdownEvent = new CountdownEvent(numThreads);

        // Start workers.
        for (var i = 0; i < numThreads; i++)
        {
            new Thread(delegate()
            {
                Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
                // Signal the CountdownEvent.
                countdownEvent.Signal();
            }).Start();
        }

        // Wait for workers.
        countdownEvent.Wait();
        Console.WriteLine("Finished.");
    }
}
Run Code Online (Sandbox Code Playgroud)


Ben*_*zar 9

如果你有一个超过64个STA线程的等待句柄,马克说.你可以用你的线程创建一个列表,并等待所有人在第二个循环中完成.

//check that all threads have completed.
foreach (Thread thread in threadList)
{
     thread.Join();

}  
Run Code Online (Sandbox Code Playgroud)


Mar*_*ers 7

如果您不在.NET 4.0上,则可以使用List < ManualResetEvent >,每个线程一个,并等待它们设置.要等待多个线程,您可以考虑使用WaitAll,但要注意64个等待句柄的限制.如果你需要更多,你可以循环遍历它们并单独等待每一个.

如果您希望更快的启动时间,则可能不需要等待在启动期间读取所有数据.只需显示GUI,任何缺失的信息都可以通过某种"正在更新..."图标或类似方式显示为灰色.当信息进入时,只需触发一个事件来更新GUI.即使在读入所有表中的所有数据之前,用户也可以开始执行许多操作.


Ben*_*zar 6

如果您喜欢冒险,可以使用C#4.0和任务并行库:

Parallel.ForEach(jobList, curJob => {
  curJob.Process()
});
Run Code Online (Sandbox Code Playgroud)