C#中的线程(二)
15.4 ThreadPlayaround示例
下面用一个简单的示例ThreadPlayaround来说明如何使用线程。这个示例的目的是介绍如何处理线程,而不是说明实际编程问题。
示例ThreadPlayaround的核心是方法DisplayNumbers(),它累加一个数字,并显示每次累加的结果。DisplayNumbers()还会显示它运行的线程名称和文化背景:
static void DisplayNumbers()
{
Thread thisThread = Thread.CurrentThread;
string name = thisThread.Name;
Console.WriteLine("Starting thread: " + name);
Console.WriteLine(name + ": Current Culture = " +
thisThread.CurrentCulture);
for (int i=1 ; i<= 8*interval ; i++)
{
if (i%interval == 0)
Console.WriteLine(name + ": count has reached " + i);
}
}
累加的数字取决于interval字段,它的值是用户输入的。如果用户输入100,就累加到800,显示数字100, 200, 300, 400, 500, 600, 700和800,如果用户输入1000,就累加到8000,显示数字1000, 2000, 3000, 4000, 5000, 6000, 7000和 8000,依次类推。这似乎是一个没有意义的方法,但它的目的是让处理器停止一段时间,以便查看处理器是如何处理这个任务的。
ThreadPlayaround示例启动了第二个工作线程,运行DisplayNumbers(),但启动这个工作线程后,主线程就开始执行同一个方法,此时我们应看到有两个累加过程同时发生。
ThreadPlayaround示例的Main()方法及其包含的类如下所示:
class EntryPoint
{
static int interval;
static void Main()
{
Console.Write("Interval to display results at?> ");
interval = int.Parse(Console.ReadLine());
Thread thisThread = Thread.CurrentThread;
thisThread.Name = "Main Thread";
ThreadStart workerStart = new ThreadStart(StartMethod);
Thread workerThread = new Thread(workerStart);
workerThread.Name = "Worker";
workerThread.Start();
DisplayNumbers();
Console.WriteLine("Main Thread Finished");
Console.ReadLine();
}
}
该代码段从类的声明开始,interval是这个类的一个静态字段。在Main()方法中,首先要求用户输入interval的值。然后获取表示主线程的线程对象引用,这样,就可以给线程指定名称,并可以在结果中看到具体的执行情况。
接着,创建工作线程,设置它的名称,启动它,给它传送一个委托,指定它必须从方法WorkerStart开始执行,最后调用DisplayNumbers()方法,开始累加。工作线程的入口是:
static void StartMethod()
{
DisplayNumbers();
Console.WriteLine("Worker Thread Finished");
}
注意所有这些方法都是类EntryPoint的静态方法。两个累加过程是完全独立的,因为DisplayNumbers()方法中用于累加数字的变量i 是一个局部变量。局部变量只能在定义它们的方法中使用,也只有在执行该方法的线程中是可见的。如果另一个线程开始执行这个方法,该线程就会获得该局部变量的副本。运行这段代码,给interval选择一个相对小的值100,得到如下结果:
ThreadPlayaround
Interval to display results at?> 100
Starting thread: Main Thread
Main Thread: Current Culture = en-US
Main Thread: count has reached 100
Main Thread: count has reached 200
Main Thread: count has reached 300
Main Thread: count has reached 400
Main Thread: count has reached 500
Main Thread: count has reached 600
Main Thread: count has reached 700
Main Thread: count has reached 800
Main Thread Finished
Starting thread: Worker
Worker: Current Culture = en-US
Worker: count has reached 100
Worker: count has reached 200
Worker: count has reached 300
Worker: count has reached 400
Worker: count has reached 500
Worker: count has reached 600
Worker: count has reached 700
Worker: count has reached 800
Worker Thread Finished
对于并行的线程而言,两个线程的执行都非常成功。主线程启动后,累加到800之后完成执行,然后启动工作线程,执行累加过程。
此处的问题是启动线程是一个主进程,在实例化一个新线程后,主线程会遇到下面的代码:
workerThread.Start();
它调用Thread.Start(),告诉Windows新线程已经准备启动,然后即时返回。在累加到800时,Windows就启动新线程,这意味着给该线程分配各种资源,执行各种安全检查。到新线程启动时,主线程已经完成了任务。
解决这个问题的方式是选择一个比较大的 interval,这样,两个线程在DisplayNumbers()方法中花费的时间会比较长,这次给interval输入1000000,得到如下所示的结果:
ThreadPlayaround
Interval to display results at?> 1000000
Starting thread: Main Thread
Main Thread: Current Culture = en-US
Main Thread: count has reached 1000000
Starting thread: Worker
Worker: Current Culture = en-US
Main Thread: count has reached 2000000
Worker: count has reached 1000000
Main Thread: count has reached 3000000
Worker: count has reached 2000000
Main Thread: count has reached 4000000
Worker: count has reached 3000000
Main Thread: count has reached 5000000
Main Thread: count has reached 6000000
Worker: count has reached 4000000
Main Thread: count has reached 7000000
Worker: count has reached 5000000
Main Thread: count has reached 8000000
Main Thread Finished
Worker: count has reached 6000000
Worker: count has reached 7000000
Worker: count has reached 8000000
Worker Thread Finished
现在就可以看出,这两个线程实际上是并行工作的。主线程启动,累加到100万,当主线程计算下一个100万时,工作线程启动,从那时起,两个线程以相同的速度累加,直到完成任务为止。
除非运行一个多处理器计算机,否则在CPU密集的任务中使用两个线程不能节省多少时间,理解这一点是很重要的。在单处理器计算机上,让两个线程都累加到800万所花的时间与让一个线程累加到1600万是相同的,甚至使用两个线程所用的时间会略长,因为要处理另一个线程,操作系统必须用一定的时间切换线程,但这种区别可以忽略不计。使用多个线程的优点有两个。首先,可以作出响应,因为一个线程在处理用户输入时,另一个线程在后台完成其他工作;第二,如果一个或多个线程所处理的工作不占用CPU时间(例如,等待从Internet中获取数据),就可以节省时间,因为其他线程可以在未激活的线程处于等待状态时执行它们的任务。