这里我附上了我用于性能测试的示例。为什么这一切之间存在如此多的差异? (这是示例控制台应用程序)
class Program
{
internal class ThreadObj
{
public ManualResetEvent signalComplete { get; set; }
public int TaskItem { get; set; }
}
static void ThreadWork(object o)
{
ThreadObj obj = (ThreadObj)o;
System.Threading.Thread.Sleep(5000);
obj.signalComplete.Set();
}
static void Main(string[] args)
{
// Using new .net 4.0 Task
Stopwatch watch = new Stopwatch();
watch.Start();
System.Collections.Concurrent.ConcurrentBag<Task> tasks = new System.Collections.Concurrent.ConcurrentBag<Task>();
Parallel.For(0, 60, i =>
{
Task t = Task.Factory.StartNew(() =>
{
System.Threading.Thread.Sleep(5000);
}, TaskCreationOptions.PreferFairness);
tasks.Add(t);
});
Console.WriteLine("Waiting for task to finish");
Task.WaitAll(tasks.ToArray());
watch.Stop();
Console.WriteLine("Complete(Tasks) : Time " + watch.ElapsedMilliseconds.ToString());
// Using Thread
watch.Reset();
watch.Start();
System.Collections.Concurrent.ConcurrentBag<ManualResetEvent> tasksThreads = new System.Collections.Concurrent.ConcurrentBag<ManualResetEvent>();
Parallel.For(0, 60, i =>
{
ManualResetEvent signal = new ManualResetEvent(false);
tasksThreads.Add(signal);
Thread t = new Thread(new ParameterizedThreadStart(ThreadWork));
t.Start(new ThreadObj() { signalComplete = signal, TaskItem = i });
});
Console.WriteLine("Waiting for task to finish");
WaitHandle.WaitAll(tasksThreads.ToArray());
watch.Stop();
Console.WriteLine("Complete(Threads) : Time " + watch.ElapsedMilliseconds.ToString());
// Using ThreadPool
watch.Reset();
watch.Start();
System.Collections.Concurrent.ConcurrentBag<ManualResetEvent> tasksThreadPools = new System.Collections.Concurrent.ConcurrentBag<ManualResetEvent>();
Parallel.For(0, 60, i =>
{
ManualResetEvent signal = new ManualResetEvent(false);
tasksThreadPools.Add(signal);
ThreadObj obj = new ThreadObj() { signalComplete = signal, TaskItem = i };
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadWork), obj);
});
Console.WriteLine("Waiting for task to finish");
WaitHandle.WaitAll(tasksThreadPools.ToArray());
watch.Stop();
Console.WriteLine("Complete(ThreadPool) : Time " + watch.ElapsedMilliseconds.ToString());
Console.ReadLine();
}
}
请提供您的建议。
这是我得到的示例输出。
Waiting for task to finish
Complete(Tasks) : Time 28050
Waiting for task to finish
Complete(Threads) : Time 5435
Waiting for task to finish
Complete(ThreadPool) : Time 15032
答案 0 :(得分:2)
你的测试用例远非一成不变。当您在threadWork方法中执行实际计算工作时,您会发现结果非常不同。 TPL在内部使用线程池,因此它是Threadpool vs Threads的问题。与Threadpool相比,TPL之所以如此不同的原因可能在于Threadpool本身的性质(稍后会再回过头来看)。
查看Threads完成所花费的时间。你的测试方法只能睡5秒,就是这样。现在另一个.43秒去了哪里?对,创建和销毁线程本身以及相关的开销包括上下文切换。 Threadpool有一个Threads队列,可以用来同时执行。这取决于Threadpool及其配置,以便在需要时创建和销毁额外的线程。当您在Threadpool中安排60个项目时,Threadpool可能不会创建60个线程来同时处理所有项目,而是使用其中的一个子项并处理每个线程的多个项目。由于您的测试方法只是休眠,这解释了线程花费的时间与使用Threadpool花费的时间之间的巨大差异。
由于TPL在内部使用Threadpool并且在您运行ThreadPool测试之前,因此可以合理地假设,在该阶段:Threadpool中可用的线程较少,但由于TPL的运行,创建了更多线程对于Threadpool,反过来,当你的Threadpool测试运行时,最初有更多线程可用,这解释了TPL和Threadpool之间的区别。
实际上,您希望尽可能多地使用Threadpool,尤其是对于计算操作。当您需要与外部资源同步(例如从Web下载内容)时,我建议不使用线程,而是使用.NET中可用的更高级异步选项之一来获取该特定资源。