.Net线程池是由CLR管理的线程集合,用户可以使用线程池创建线程,而创建线程的数量,销毁线程的时机均由CLR管理。
线程池适用于处理时间较短的线程操作,可以节省系统反复创建、删除线程的开销。CLR初始化时,线程池中没有线程,直至线程池所维护的操作请求队列出现第一个异步操作记录项,线程池创建第一个线程。该线程执行完毕后,线程不会立即删除,CLR会对空闲线程进行删除。
线程池不适用于长时间计算密集性操作,同时,缺乏通知异步操作完成,以及返回操作结果的机制。
public static void AsynThreadPool()
{
const int x = 1;
const int y = 2;
const string lambdaState = "lambda state 2";
//先在线程池放入函数
System.Threading.ThreadPool.QueueUserWorkItem(AsyncOperation);
Sleep(TimeSpan.FromSeconds(1));
// 再次放入参数
System.Threading.ThreadPool.QueueUserWorkItem(AsyncOperation, "asyncState");
// Sleep(TimeSpan.FromSeconds(1));
//lambda
System.Threading.ThreadPool.QueueUserWorkItem(state =>
{
Console.WriteLine("Operation state" + state.ToString());
Console.WriteLine("Worker thread id" + CurrentThread.ManagedThreadId.ToString());
// Sleep(TimeSpan.FromSeconds(2));
}, "lambda state");
//闭包
System.Threading.ThreadPool.QueueUserWorkItem(_ =>
{
Console.WriteLine("Operation state" + x.ToString() + "+" + y.ToString() + "," + lambdaState.ToString());
Console.WriteLine("Worker thread id:" + CurrentThread.ManagedThreadId.ToString());
}, "lambda state2");
Sleep(TimeSpan.FromSeconds(2));
}
static void Main(string[] args)
{
CancellationTokenSource cts = new CancellationTokenSource();
// 注册 cts.Cancel() 执行后的回调方法
cts.Token.Register(() => { Console.WriteLine(" CancellationTokenSource is Register"); });
System.Threading.ThreadPool.QueueUserWorkItem(_=>
{
Sleep(1000);
if (cts.IsCancellationRequested)
{
Console.WriteLine("Sleep 1000s, Thread is cancel");
return;
}
Console.WriteLine("Sleep 1000s, Thread isn't cancel");
});
System.Threading.ThreadPool.QueueUserWorkItem(_ =>
{
Sleep(100);
if (cts.IsCancellationRequested)
{
Console.WriteLine("Sleep 100s, Thread is cancel");
return;
}
Console.WriteLine("Sleep 100s, Thread isn't cancel");
});
System.Threading.ThreadPool.QueueUserWorkItem(_ =>
{
if (cts.IsCancellationRequested)
{
Console.WriteLine("Thread is cancel");
return;
}
Console.WriteLine("Thread isn't cancel");
});
Thread.Sleep(10);
cts.Cancel();
Console.ReadLine();
}
也可用cts.Token 作为参数传入异步方法
比线程池更抽象的概念,可以通过线程或不通过线程实现并发操作。Task 概念由 .Net Framework4.0 引入,是并行编程库(Task Parallel Library,简称 TPL)的一部分。
Task 是可组合的—利用延续,可同时启动多个任务,待所有任务执行完毕后,启动另一个任务处理之前任务的结果。
Task.Run(()=>{ Console.WriteLine("Start Task");});
var task2 = new Task(() => Console.WriteLine("Start Task"));
task2.Start();
Task.Factory.StartNew(() => Console.WriteLine("Start Task"));
var task = Task.Run(() => Console.WriteLine("Start Task"));
//显式阻塞当前线程,等待task执行完毕
task.Wait();
Task<Int32> t = new Task<int>(n =>
{
Thread.Sleep(1000);
var result = 0;
var input = int.Parse(n.ToString());
for (int i = 0; i < input; i++)
{
result += i;
}
return result;
}, 100000);
Console.WriteLine($"Task has started!");
t.Start();
//阻塞当前线程,等待任务返回结果
Console.WriteLine($"Task result is {t.Result}");
Console.WriteLine($"Current thread has been blocked");
// 利用 CancellationTokenSource 作为取消标志,取消任务。
CancellationTokenSource cts = new CancellationTokenSource();
Task<Int32> t = new Task<int>(() =>
{
var result = 0;
for (int i = 0; i < 10000; i++)
{
if (cts.IsCancellationRequested)
return result;
result += i;
Thread.Sleep(2);
}
return result;
});
Console.WriteLine($"Task has started!");
t.Start();
Thread.Sleep(10);
Console.WriteLine($"cts has been canceled");
cts.Cancel();
try
{
// 捕获异常后,打印任务结果
Console.WriteLine($"Task result is {t.Result}");
}
catch (AggregateException ex)
{
//取消任务后,会抛出OperationCanceledException
Console.WriteLine($"Task has been canceled");
}
CancellationToken 可以直接传入Task匿名函数中,为什么重写Task函数,将CancellationToken 作为参数传入?
因为当任务开始前,取消标志位为已取消状态,通过参数传递,会在Task.Start()执行时得到InvalidOperationException异常。而Task操作中调用CancellationToken , 是巡检在任务执行过程中, CancellationToken 时候置为取消状态。
public Task(Func<TResult> function, CancellationToken cancellationToken);
这是任务较于线程池具有优势的地方,采用Task.WhenAll()等待所有任务执行完毕后,执行下一个操作;
采用Task.WhenAny(),等待任意一个任务完成或由于超时而结束后,执行下一个操作。此处,可以借助取消标志位一起,优化任务执行超时的问题。
var task1 = Task<string>.Run(()=> { Thread.Sleep(100); return "Start1 Task"; });
var task2 = Task<string>.Run(()=> { Thread.Sleep(10); return "Start2 Task"; });
var task3 = Task.WhenAll(new[] { task1, task2 });
task3.ContinueWith(t3 => { Console.WriteLine($"{t3.Result[0]}--{t3.Result[1]} are All Done !"); });
var task4 = Task.WhenAny(new[] { task1, task2 });
task4.ContinueWith(t4 => { Console.WriteLine(t4.Result.Result+" is First !"); });
采用TaskCreationOptions.LongRunning, 提议TaskScheduler(任务调度程序)避免使用池化线程执行长时间的计算密集型操作。
《果壳中的C#》《CLR via C#》《C#多线程编程实战》
14.并发与异步 - 3.C#5.0的异步函数 -《果壳中的c#》
C# 5.0 Async函数的提示和技巧