使用线程池(1)
在线程池中调用委托
为什么要使用线程池?
创建线程是昂贵的操作,所以为每个短暂的异步操作创建线程会产生显著的开销。为了解决该问题,有一个常用的方式叫池(pooling)。线程池可以成功的适应于任何需要大量短暂的开销大的资源的情形。
注意事项:
- 每个CLR都有一个线程池实例;
- 保持线程中的操作都是短暂的是非常重要的。不要在线程池中放入长时间运行的操作或者阻塞线程,否则会产生性能问题和非常难以调试的错误;
- 线程池中的工作线程都是后台线程。
以下是代码实践:
using System;
using System.Threading;
namespace 在线程池中调用委托
{
internal class Program
{
private static void Main()
{
var threadId = 0;
RunOnThreadPool poolDelegate = Test;
//线程的构造函数只接受一个无返回值得方法,所以用lambda表达式将Test方法的调用包起来。
var t = new Thread(() => Test(out threadId));
t.Start();
t.Join();
//Thread.Sleep(TimeSpan.FromSeconds(2));
Console.WriteLine("Thread id: {0}", threadId);
/*委托的异步调用,在线程池的子线程中执行委托Test函数和Callback函数在线程池中很可能在同一线程上执行,
* BeginInvoke接受一个回调函数,异步操作完成后调用回调函数,"a delegate asynchrous call"用户自定义
* 状态传递给回调函数
*/
var r = poolDelegate.BeginInvoke(out threadId, Callback, "a delegate asynchrous call");
r.AsyncWaitHandle.WaitOne();//等待操作完成,可省略,因为EndInvoke方法会等待异步操作的完成
/*Test异步调用完成后,立即执行下一步操作,不等待回调函数的完成,
* EndInvoke方法会等待异步操作的完成,
* EndInvoke方法会将任何未处理的异常抛到调用线程里,所以Begin和End要配对使用。
*/
var result = poolDelegate.EndInvoke(out threadId, r);
//Thread.Sleep(TimeSpan.FromSeconds(2));
Console.WriteLine("Thread pool worker thread id: {0}", threadId);
Console.WriteLine(result);
//Thread.Sleep(TimeSpan.FromSeconds(2));
Console.ReadKey();
}
private delegate string RunOnThreadPool(out int threadId);
private static void Callback(IAsyncResult ar)
{
Console.WriteLine("Starting a callback...");
Console.WriteLine("State passed to a callback: {0}", ar.AsyncState);
Console.WriteLine("Is thread pool thread: {0}", Thread.CurrentThread.IsThreadPoolThread);
Console.WriteLine("Thread pool worker thread id: {0}", Thread.CurrentThread.ManagedThreadId);
}
private static string Test(out int threadId)
{
Console.WriteLine("Starting...");
Console.WriteLine("Is thread pool thread: {0}", Thread.CurrentThread.IsThreadPoolThread);
Thread.Sleep(TimeSpan.FromSeconds(2));
threadId = Thread.CurrentThread.ManagedThreadId;
return string.Format("Thread pool worker id was: {0}", threadId);
}
}
}
总结
使用BeginOperationName/EndOperationName方法和.NET中的IAsyncResult对象等方式被称为异步编程模型(APM),这样的方法称为异步方法。现代编程中更推荐任务并行库(Task Parallel Library简称TPL)
备注:学习《Multithreading in C# 5.0 Cookbook》Eugene Agafonov著的总结,以备日后查询。