前言:看了书上两个使用C#4.0并行编程的demo,又对照以前收藏的网上几篇讲述线程池的雄文,一并整理,写个示例总结一下。写这篇文章的时候,发现关于线程的好几个基础的重要的知识点自己都不熟悉,而且可能习惯性认知浅薄,所以痛苦的无以复加,不知道到底要说什么。不想看文章的可以直接下载最后的示例,本文代码主要参考Marc Clifton的“.NET's ThreadPool Class - Behind The Scenes”,对新手也许有帮助。
参考:
http://msdn.microsoft.com/zh-cn/library/system.threading.threadpool(VS.80).aspx
http://www.codeproject.com/KB/threads/threadtests.aspx
http://www.codeproject.com/KB/threads/smartthreadpool.aspx
http://blog.zhaojie.me/2009/07/thread-pool-1-the-goal-and-the-clr-thread-pool.html (老赵的浅谈线程池上中下三篇)
先大概看一下控制台应用程序的Main方法的主要代码:
static bool done = false;
static decimal count2 = 0;
static int threadDone = 0;//标志启用线程数?
static System.Timers.Timer timer = new System.Timers.Timer(1000);
static decimal[] threadPoolCounters = new decimal[10];
static Thread[] threads = new Thread[10];
static System.Timers.Timer[] threadTimers = new System.Timers.Timer[10];
static void Main(string[] args)
{
timer.Stop();
/*当 AutoReset 设置为 false 时,Timer 只在第一个 Interval 过后引发一次 Elapsed 事件。
若要保持以 Interval 时间间隔引发 Elapsed 事件,请将 AutoReset 设置为 true。*/
timer.AutoReset = false;
timer.Elapsed += new ElapsedEventHandler(OnTimerEvent);//当timer.Start()时,触发事件
decimal total = 0;
// raw test
decimal count1 = SingleThreadTest();//单一线程,一跑到底
Console.WriteLine("Single thread count = " + count1.ToString());
// create one thread, increment counter, destroy thread, repeat
Console.WriteLine();
CreateAndDestroyTest();//创建一个线程,运算,
然后销毁该线程 重复
前面的动作
Console.WriteLine("Create and destroy per count = " + count2.ToString());
// Create 10 threads and run them simultaneously
//一次性创建10个线程,然后遍历使线程执行运算
Console.WriteLine();
InitThreadPoolCounters();
InitThreads();
StartThreads();
while (threadDone != 10) { };
Console.WriteLine("10 simultaneous threads:");
for (int i = 0; i < 10; i++)
{
Console.WriteLine("T" + i.ToString() + " = " + threadPoolCounters[i].ToString() + " ");
total += threadPoolCounters[i];
}
Console.WriteLine("Total = " + total.ToString());
Console.WriteLine();
Console.WriteLine("///////////////////////////////////////////////////");
// using ThreadPool
//直接通过线程池的QueueUserWorkItem方法,按队列执行10个任务
Console.WriteLine();
Console.WriteLine("ThreadPool:");
InitThreadPoolCounters();
QueueThreadPoolThreads();
while (threadDone != 10) { };
Console.WriteLine("ThreadPool: 10 simultaneous threads:");
total = 0;
for (int i = 0; i < 10; i++)
{
// threadTimers[i].Stop();
// threadTimers[i].Dispose();
Console.WriteLine("T" + i.ToString() + " = " + threadPoolCounters[i].ToString() + " ");
total += threadPoolCounters[i];
}
Console.WriteLine("Total = " + total.ToString());
// using SmartThreadPool
//通过Amir Bar的SmartThreadPool线程池,利用QueueUserWorkItem方法,按队列执行10个任务
Console.WriteLine();
Console.WriteLine("SmartThreadPool:");
InitThreadPoolCounters();
QueueSmartThreadPoolThreads();
while (threadDone != 10) { };
Console.WriteLine("SmartThreadPool: 10 simultaneous threads:");
total = 0;
for (int i = 0; i < 10; i++)
{
Console.WriteLine("T" + i.ToString() + " = " + threadPoolCounters[i].ToString() + " ");
total += threadPoolCounters[i];
}
Console.WriteLine("Total = " + total.ToString());
// using ManagedThreadPool
//通过Stephen Toub改进后的线程池,利用QueueUserWorkItem方法,按队列执行10个任务
Console.WriteLine();
Console.WriteLine("ManagedThreadPool:");
InitThreadPoolCounters();
QueueManagedThreadPoolThreads();
while (threadDone != 10) { };
Console.WriteLine("ManagedThreadPool: 10 simultaneous threads:");
total = 0;
for (int i = 0; i < 10; i++)
{
Console.WriteLine("T" + i.ToString() + " = " + threadPoolCounters[i].ToString() + " ");
total += threadPoolCounters[i];
}
Console.WriteLine("Total = " + total.ToString());
// using C#4.0 Parallel
//通过Tasks.Parallel.For进行并行运算
Console.WriteLine();
Console.WriteLine("Parallel:");
InitThreadPoolCounters();
UseParallelTasks();
while (threadDone != 10) { };
Console.WriteLine("Parallel: 10 simultaneous threads:");
total = 0;
for (int i = 0; i < 10; i++)
{
Console.WriteLine("T" + i.ToString() + " = " + threadPoolCounters[i].ToString() + " ");
total += threadPoolCounters[i];
}
Console.WriteLine("Total = " + total.ToString());
}
我们可以先熟悉一下大致思路。代码中,我们主要依靠输出的数字count或者total来判断哪个方法执行效率更高(原文是How Hign Can I Count?),通常输出的数字越大,我们就认为它”干的活越多“,效率越高。主要实现过程就是通过一个静态的System.Timers.Timer对象的timer实例,设置它的Interval属性和ElapsedEventHandler事件:
static System.Timers.Timer timer = new System.Timers.Timer(1000);
/*当 AutoReset 设置为 false 时,Timer 只在第一个 Interval 过后引发一次 Elapsed 事件。
若要保持以 Interval 时间间隔引发 Elapsed 事件,请将 AutoReset 设置为 true。*/
timer.AutoReset = false;
timer.Elapsed += new ElapsedEventHandler(OnTimerEvent);//当timer.Start()时,触发事件
其中,timer的事件触发的函数:
static void OnTimerEvent(object src, ElapsedEventArgs e)
{
done = true;
}
每次timer.Start执行的时候,一次测试就将开始,这样可以确保测试的不同方法都在1000毫秒内跑完。
下面开始具体介绍几个方法:
A、线程
这个非常简单,就是通过主线程计算在1000毫秒内,count从0递增加到了多少:
/// <summary>
/// 单一线程,一跑到底
/// </summary>
/// <returns></returns>
static decimal SingleThreadTest()
{
done = false;
decimal counter = 0;
timer.Start();
while (!done)
{
++counter;
}
return counter;
}
while判断可以保证方法在1000毫秒内执行完成。
B、多线程
这个多线程方法比较折腾,先创建线程,然后运行,最后销毁线程,这就是一个线程执行单元,重复10次这个线程执行单元。
/// <summary>
/// 创建一个线程,运算,然后销毁该线程 重复前面的动作
/// </summary>
static void CreateAndDestroyTest()
{
done = false;
timer.Start();
while (!done)
{
Thread counterThread = new Thread(new ThreadStart(Count1Thread));
counterThread.IsBackground = true;//后台线程
counterThread.Start();
while (counterThread.IsAlive) { };
}
}
那个ThreadStart委托对应的方法Count1Thread如下:
static void Count1Thread()
{
++count2; //静态字段count2自增
}
从表面上看,大家估计都可以猜到,效果可能不佳。
C、还是多线程
这个方法不判断线程的执行状态,不用等到一个线程销毁后再创建一个线程,然后执行线程方法。线程执行的方法就是根据线程的Name找到一个指定数组的某一索引,并累加改变数组的值:
static void InitThreadPoolCounters()
{
threadDone = 0;
for (int i = 0; i < 10; i++)
{
threadPoolCounters[i] = 0;
}
}
/// <summary>
/// 初始化10个线程
/// </summary>