示例threadpool:
public class Example {
public static void Main() {
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc)); //task 1
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc)); //task 2
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc)); //task 3
Console.WriteLine("Main thread does some work, then sleeps.");
Thread.Sleep(1000);
Console.WriteLine("Main thread exits.");
}
static void ThreadProc(Object stateInfo) {
Console.WriteLine("Hello from the thread pool.");
}
}
示例信号量:
public class Example
{
private static Semaphore _pool;
private static int _padding;
public static void Main()
{
_pool = new Semaphore(0, 3);
// Create and start five numbered threads.
//
for(int i = 1; i <= 5; i++)
{
Thread t = new Thread(new ParameterizedThreadStart(Worker));
t.Start(i);
}
Thread.Sleep(500);
Console.WriteLine("Main thread calls Release(3).");
_pool.Release(3);
Console.WriteLine("Main thread exits.");
}
private static void Worker(object num)
{
Console.WriteLine("Thread {0} begins " +
"and waits for the semaphore.", num);
_pool.WaitOne();
int padding = Interlocked.Add(ref _padding, 100);
Console.WriteLine("Thread {0} enters the semaphore.", num);
Thread.Sleep(1000 + padding);
Console.WriteLine("Thread {0} releases the semaphore.", num);
Console.WriteLine("Thread {0} previous semaphore count: {1}",
num, _pool.Release());
}
}
我猜是信号量的一些开销,在这个例子中创建5个线程,但是线程池使用内置的"线程池"(它将使用现有的线程,如后台工作线程)。这是正确的还是更多的,如果你只是想要一个简单的线程池,但速度和性能是一个问题,使用信号量是否有任何真正的优势?
你在比较苹果和牛。
ThreadPool允许在小任务中使用线程。它缺乏任何方便的会合机制(Sleep(1000)是解决该问题的弱解决方案)。
信号量是同步线程的一种方式,它们可以是ThreadPool线程。
仅当您希望这些线程长时间运行时才创建和管理显式线程,或者您需要让该线程尽快执行。即使这样,您可能最好使用任务并行库并将任务标记为长时间运行。
线程池维护一个空闲的"活动"线程池。所以当你调用QueueUserWorkItem
时,很有可能会有一个空闲线程,它可以抓取你的工作然后离开。这并不总是正确的,但通常是正确的。当你创建一个新的线程(比如var t = new Thread(...)
),总是有一些启动开销。
此外,线程池允许您设置池线程的最大数量,并管理工作负载。因此,如果允许4个池线程并对10个工作项进行排队,那么线程池将确保一次只运行4个池线程。在某些方面,您可以将其视为隐式信号量,因为它不会让超过四个线程同时运行。但是它允许您按照自己的需要进行排队(在一些大的系统定义的限制内)。