线程池
线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认堆栈大小,以默认的优先级运行,并处于多线程单元中。如果某个线程在托管代码中空闲(如正在等待某个事件),则线程池将插入另一个辅助线程来使所有处理器保持繁忙。如果所有线程池线程都始终保持繁忙,但队列中包含挂起的工作,则线程池将在一段时间之后创建另一个辅助线程。但线程的数目永远不会超过最大值。超过最大值的其他线程可以排队,但它们要等到其他线程完成后才启动。将一个异步的、计算限制的操作放到线程池的队列中调用:
public static Boolean QueueUserWorkItem(WaitCallback wc, Object state);
public static Boolean QueueUserWorkItem(WaitCallback wc);该方法的执行顺序则有Windows调试器决定。
WaitCallback定义如下:
public delegate void WaitCallback(Object state);可以通过state来向任务过程传递参数。如果任务过程需要多个参数,可以定义包含这些数据的类,并将类的实例转换为Object数据类型
执行上下文: 每个线程都关联了一个执行上下文数据结构。执行上下文包括:安全设置、宿主设置以及逻辑调用上下文数据; 线程执行代码时,有的操作会受到线程的执行上下文设置的影响。理想情况下,每当一个线程(初始线程)使用另一个线程(辅助线程)执行任务时,前者的执行上下文应该流向辅助线程。这就确保了辅助线程执行任何操作使用的是相同的安全设置和宿主设置,保证了初始线程的逻辑调用上下文可以在辅助线程中使用。在“流”的过程中会有性能损失。System.Threading ExecutionContext允许控制线程的执行上下文的流动。
协作式取消: 对于长时间运行的计算限制操作可以设置支持取消能力。
System.Threading.CancellationTokenSource类
CancellationTokenSource cts=new CancellationTokenSource();
ThreadPool.QueueUserWorkItem(o=>Count(cts.Token,1000));
cts.Cancel();
也可以通过链接另一组CancellationTokenSource来新建一个CancellationTokenSource对象:var canToken = CancellationTokenSource.CreateLinkedTokenSource(cts.Token);其他的被取消,这个新的也将被取消。
任务: ThreadPoor的QueueUserWorkItem没有一个内建机制让我们知道操作什么时候完成和操作完成时获得一个返回值Threading.Tasks则解决了这些问题。
static void Main(string[] args)
{
//ThreadPool.QueueUserWorkItem(Wait, 5);
Task t = new Task(Wait, 5);
t.Start();
Console.ReadKey();
}
static void Wait(object obj)
{
Console.WriteLine(obj);
}
1 等待任务完成并获取它的结果
static void Main(string[] args)
{
Task<int> t = new Task<int>(n => Count(n), 100);
t.Start();
t.Wait();
Console.Write(t.Result);
Console.ReadKey();
}
static int Count(object obj)
{
int num = (int)obj;
for (int i = 0; i < num; i--) ;
return num;
}
2 取消任务
static void Main(string[] args)
{
CancellationTokenSource cts = new CancellationTokenSource();
Task<int> t = new Task<int>(n => Count(cts.Token, (int)n), 100);
t.Start();
//t.Wait();
cts.Cancel();
try
{
//如果已经取消了,就会抛出异常
Console.Write("返回值是:"+t.Result);
}
catch (AggregateException ae)
{
ae.Handle(e => e is OperationCanceledException);
Console.WriteLine("Count is cancelled");
}
Console.ReadKey();
}
static int count = 0;
static int Count(CancellationToken token, int num)
{
for (int i = 0; i < num; i++)
{
count++;
Thread.Sleep(100);
if (token.IsCancellationRequested)
{
// Console.WriteLine("Count is cancelled");
break;
}
}
return count;
}
3 一个任务完成时自动启动一个新任务
Task<int> t = new Task<int>(n => Count(n), 100);
t.Start();
t.ContinueWith(c=>Console.WriteLine("the Result is :"+t.Result));
4 任务可以启动子任务
Task<int[]> parent = new Task<int[]>(() =>
{
var result = new int[3];
new Task(() => result[0] = Count(100), TaskCreationOptions.AttachedToParent).Start();
new Task(() => result[1] = Count(99), TaskCreationOptions.AttachedToParent).Start();
new Task(() => result[2] = Count(98), TaskCreationOptions.AttachedToParent).Start();
return result;
});
parent.ContinueWith(pTask => Array.ForEach(pTask.Result, Console.WriteLine));
parent.Start();
Console.ReadKey();
5 不要用for foreach 去循环执行任务。而应该用Parallel的静态方法For和Foreach让多个线程池处理(For更快)。
Parallel.Invoke(()=>Method1(),()=>Method2);并行处理方法。