c#多线程问题等待线程

时间:2016-07-06 15:23:47

标签: c# multithreading

在审查了这个论坛上的很多帖子以及其他关于c#多线程的帖子后,我仍然感到困惑,并且在处理手头的问题时遇到了问题。

我想创建numThreads个线程来为documentIds中的每个整数执行一个函数。 documentIds是一个List<int>,其Count = 100,我想在documentIds中的每个元素上调用RestitchWorker.Restitch。

我目前的情况如下,但我对于如何保持5个线程以及在100个documentIds列表中循环感到困惑...所有帮助都表示赞赏。

for (int i = 0; i < documentIds.Count; i++)
{
    if (threadCount < numThreads)
    {
        var Worker = new RestitchWorker(documentIds.ElementAt(i));
        Thread t_restitchWorker = new Thread(() => Worker.Restitch());
        threadCount++;
        t_restitchWorker.Start();
        t_restitchWorker.Join();
     }
}

2 个答案:

答案 0 :(得分:5)

这个问题确实更适合于任务而非线程。如果你的问题明确地创建线程是没有必要的;然后线程池可以更高效,因为线程管理可能很昂贵。

任务适合需要松散地并行实现100个长作业的问题,因为它们将汇集线程而不是创建100个显式线程,并且具有支持等待多个任务的易于使用的API。

任务列表

您可以通过创建任务列表并调用System.Threading.Tasks.Task.WaitAll来执行此操作:

var tasks = new List<Task>();

for (int i = 0; i < n; ++i)
{
    tasks.Add(Task.Run(action: SomeLongTask));
}

Task.WaitAll(tasks);

<强>的Parallel.For

然而,更好的方法是这样做,因为它在for循环中你需要传递一个整数就是使用System.Threading.Tasks.Parallel.For

Parallel.For(0, n, (i) =>
{
   SomeLongTask(i); 
});

答案 1 :(得分:2)

有许多机制可以对应用程序进行多线程处理。您可以使用异步任务,任务并行库(TPL),线程池,信号量等。当我需要对我一次生成多少线程的高度控制时,我使用的机制是使用SemaphoreSlim ,设置最大线程数,然后使用Wait等待新线程变为可用。我将我的数据(例如文档ID列表)放入ConcurrentQueue,以便我可以安全地排队和出列我的线程需要执行工作的信息,而不必担心(太多)线程安全。异步任务可用于实际开始执行工作。

static class Program
{
    private const int _maxWorkers = 10;
    private static readonly SemaphoreSlim _threadManager = new SemaphoreSlim(_maxWorkers);

    private void DoStuff()
    {
        var queue = new ConcurrentQueue<int>(SomeClass.GetDocumentIds());
        var operations = new List<Task>();

        while (!queue.IsEmpty)
        {
            int documentId;

            if (queue.TryDequeue(out documentId))
            {
                _threadManager.Wait(); // this will block after max number of threads is met
                try
                {
                    operations.Add(GetDocument(documentId);
                }
                catch (Exception)
                {
                    // ignored
                }
            }
        }

        Task.WaitAll(operations.ToArray()); // finally, this waits till the last remaining tasks are complete
    }

    private static async Task GetDocument(int documentId)
    {
        await Task.Yield();

            try
            {
                GoGetDocument(documentId);
            }
            catch (Exception)
            {
                // ignored
            }
            finally
            {
                _threadManager.Release(); // release the semaphore when the task completes
            }

    }