【发布时间】:2014-06-11 06:44:23
【问题描述】:
我需要在另一个线程中处理数据。可以通过两种方式完成:
-
使用线程循环等待事件:
AutoResetEvent e = new AutoResetEvent(false) Thread t = new Thread(delegate { while(true) { e.WaitOne(); // process data } };) void OnProgramStarted() // one time { t.Start(); } void OnDataReceived() { // put data to queue e.Set(); } -
使用线程池:
void ProcessData(object state) { // process data } void OnDataReceived() { // put data to queue ThreadPool.QueueUserWorkItem(ProcessData); }
什么方法会更快?
真实的测试给出了模棱两可的结果。
我的基准测试代码:
using System;
using System.Diagnostics;
using System.Threading;
namespace t_event_tpool
{
class Program
{
const int t = 1000000;
static Stopwatch sw = new Stopwatch();
static int q1, q2;
static AutoResetEvent e1 = new AutoResetEvent(false);
static AutoResetEvent done1 = new AutoResetEvent(false);
static Thread thread = new Thread(ThreadProc);
static void ThreadProc(object state)
{
while(true)
{
e1.WaitOne();
q1++;
done1.Set();
}
}
static AutoResetEvent done2 = new AutoResetEvent(false);
static void PoolProc(object state)
{
q2++;
done2.Set();
}
static void TestA()
{
sw.Restart();
for(int i = 0; i < t; i++)
{
e1.Set();
done1.WaitOne();
}
sw.Stop();
Console.WriteLine("a " + sw.ElapsedMilliseconds + "\t" + q1);
}
static void TestB()
{
sw.Restart();
for(int i = 0; i < t; i++)
{
ThreadPool.QueueUserWorkItem(PoolProc, i);
done2.WaitOne();
}
sw.Stop();
Console.WriteLine("b " + sw.ElapsedMilliseconds + "\t" + q2);
}
static void Main(string[] args)
{
thread.IsBackground = true;
thread.Start();
TestA();
TestB();
TestA();
TestB();
TestA();
TestB();
}
}
}
在低 CPU 负载下(没有其他应用程序)TestB 比 TestA 快 2 倍。在其他进程的 CPU 负载较高时,TestA 比 TestB 更快。
【问题讨论】:
-
很可能是线程池方法,因为线程池旨在加快线程的初始化时间。
-
我有固定的代码。当然,线程只在程序启动时初始化一次。
-
看起来
BlockingCollection<T>是一个选项:一个线程(主线程?)向其中添加数据,另一个线程获取并处理数据。 -
QUWI 相当快,但不如可以立即继续运行的线程快。如果您得到“模棱两可的结果”,那么请不要打扰并偏爱 QUWI。
-
我认为线程也应该更快。但测试表明,在低 CPU 负载下(没有其他应用程序)QUWI 速度快 1.5-2 倍。如果 CPU 负载很高(其他应用程序),则测试结果相反。我不明白为什么会这样。也许我的测试不正确。
标签: c# multithreading threadpool