C# 如何维护固定的线程集合?

C# 如何维护固定的线程集合?,c#,multithreading,c#-3.0,C#,Multithreading,C# 3.0,需要建议c#3.0中多线程的最佳方法(无并行或任务) 情况是,我有一个500件物品的队列。在特定时间,我只能运行10个线程(最多)。下面是我的代码 While (queue.Count > 0) { Thread[] threads = new Thread[no_of_threads]; for (int j = 0; j < no_of_threads; j++) { threads[j] = new Thread(StartProcessing);//StartProc

需要建议c#3.0中多线程的最佳方法(无并行或任务)

情况是,我有一个500件物品的队列。在特定时间,我只能运行10个线程(最多)。下面是我的代码

While (queue.Count > 0)
{
Thread[] threads = new Thread[no_of_threads];
for (int j = 0; j < no_of_threads; j++)
 {
   threads[j] = new Thread(StartProcessing);//StartProcessing Dequeue one item each time //for a single thread
   threads[j].Start();
 }

 foreach (Thread objThread in threads)
 {
   objThread.Join();
 }
}
While(queue.Count>0)
{
线程[]线程=新线程[没有线程];
对于(int j=0;j
这种方法的问题是,例如,如果没有线程中的线程=10个,并且其中9个线程完成了处理,而1个线程仍在工作,那么在所有10个线程都完成之前,我无法退出循环并将工作委托给空闲线程


我需要始终有10个线程工作,直到队列计数>0。

这是一个简单的生产者-消费者场景。您需要这样一个线程安全队列:-10个线程可以在循环中逐个读取和处理作业,直到队列为空。
根据您填充队列的方式(在开始处理队列之前或处理队列时),您可以在队列变空或通过停止标志发出停止信号时立即结束这些线程。在后一种情况下,您可能需要唤醒线程(例如使用虚拟作业)。

这是一个简单的生产者-消费者场景。您需要这样一个线程安全队列:-10个线程可以在循环中逐个读取和处理作业,直到队列为空。
根据您填充队列的方式(在开始处理队列之前或处理队列时),您可以在队列变空或通过停止标志发出停止信号时立即结束这些线程。在后一种情况下,您可能需要唤醒线程(例如使用虚拟作业)。

与其从外部控制线程,不如让每个线程自己使用数据

伪代码:

create 10 threads

thread code:
    while elements in queue
    get element from queue
    process element

让每个线程自己使用数据,而不是从外部控制线程

伪代码:

create 10 threads

thread code:
    while elements in queue
    get element from queue
    process element
您应该使用它来为您管理和优化线程

一旦池中的线程完成其任务,它将返回到等待线程的队列,在那里可以重用它。这种重用使应用程序能够避免为每个任务创建新线程的成本

线程池通常具有最大数量的线程。如果所有线程都很忙,则会将其他任务放入队列中,直到它们可以在线程可用时得到服务

最好不要干涉
ThreadPool
,因为它足够智能地管理和分配线程。但是,如果您确实需要这样做,您可以使用您应该使用的方法来设置最大线程数的约束,该方法为您管理和优化线程

一旦池中的线程完成其任务,它将返回到等待线程的队列,在那里可以重用它。这种重用使应用程序能够避免为每个任务创建新线程的成本

线程池通常具有最大数量的线程。如果所有线程都很忙,则会将其他任务放入队列中,直到它们可以在线程可用时得到服务


最好不要干涉
ThreadPool
,因为它足够智能地管理和分配线程。但是,如果确实需要这样做,可以使用方法设置最大线程数的约束,因此只需处理一个队列,该队列设计为从多LPE线程访问。你是在使用.NET4.0吗?我想说是使用
BlockingCollection
。它不仅工作得很好,而且效率很高。您可以非常简单地创建自己的类,它只是一个
队列
,对所有方法进行
锁定
调用。它也可以工作,但效率不高。(但对于您的目的来说,它可能足够有效,并且“正确”地重新编写BlockingCollection将非常困难。)


一旦您拥有了该队列,每个工作人员就可以从该队列中获取一个项目,对其进行处理,然后向该队列请求另一个项目。当没有更多的时候,你不需要担心结束那条线;它已经没有更多的工作可做了。

因此,您只需要处理一个队列,该队列设计用于从多LPE线程访问。你是在使用.NET4.0吗?我想说是使用
BlockingCollection
。它不仅工作得很好,而且效率很高。您可以非常简单地创建自己的类,它只是一个
队列
,对所有方法进行
锁定
调用。它也可以工作,但效率不高。(但对于您的目的来说,它可能足够有效,并且“正确”地重新编写BlockingCollection将非常困难。)


一旦您拥有了该队列,每个工作人员就可以从该队列中获取一个项目,对其进行处理,然后向该队列请求另一个项目。当没有更多的时候,你不需要担心结束那条线;没有更多的工作可以做了。

这是一个简单的方法

其思想是创建一个最大计数为N的信号量,其中N是允许的线程数。循环等待信号量,并在获取信号量时对任务排队

Semaphore ThreadsAvailable = new Semaphore(10, 10);
while (Queue.Count > 0)
{
    ThreadsAvailable.WaitOne();
    // Must dequeue item here, otherwise you could run off the end of the queue
    ThreadPool.QueueUserWorkItem(DoStuff, Queue.Dequeue());
}

// Wait for remaining threads to finish
int threadCount = 10;
while (threadCount != 0)
{
    ThreadsAvailable.WaitOne();
    --threadCount;
}


void DoStuff(object item)
{
    ItemType theItem = (ItemType)item;
    // process the item
    StartProcessing(item);
    // And then release the semaphore so another thread can run
    ThreadsAvailable.Release();
}
该项在主循环中退出队列,因为这样可以避免竞争条件,否则将很难处理。如果让线程将该项出列,则线程必须执行以下操作:

lock (queue)
{
    if (queue.Count > 0)
        item = queue.Dequeue();
    else
        // There wasn't an item to dequeue
        return;
}
否则,当队列中只剩下一个项目时,可能会发生以下事件序列

main loop checks Queue.Count, which returns 1
main loop calls QueueUserWorkItem
main loop checks Queue.Count again, which returns 1 because the thread hasn't started yet
new thread starts and dequeues an item
main loop tries to dequeue an item and throws an exception because queue.Count == 0
如果你愿意这样处理事情,那你就没事了。关键是确保线程在退出之前调用信号量上的
Release
。您可以使用显式管理的线程,或者使用我发布的
ThreadPool
方法来实现这一点。我刚刚使用了
ThreadPool
,因为我发现它比显式管理线程更容易。

<