TASK首次引入.net Framework 4中,Task对象通常是以异步方式执行于线程池上,是基于ThreadPool的,您可以使用 Status 属性,以及 IsCanceled,IsCompleted和 IsFaulted 属性,以确定任务的状态,Task是目前最为推崇的多线程方法
//常规启动
Task.Run(() => DoSomeThing());
//也可以用其构造函数启动
new Task(() => DoSomeThing()).Start();
//工厂方式启动
Task.Factory.StartNew(() => DoSomeThing());
以上几种启动方式没有什么优劣差别
#region waitAny waitAll
{
//动物界举办了第二届赛跑比赛,参赛的有兔子,乌龟,老虎,大象,长颈鹿
Console.WriteLine("动物界举办了第二届赛跑比赛,参赛的有兔子,乌龟,老虎,大象,长颈鹿");
List
tasks.Add(Task.Run(() => Race("兔子")));
tasks.Add(Task.Run(() => Race("乌龟")));
tasks.Add(Task.Run(() => Race("老虎")));
tasks.Add(Task.Run(() => Race("大象")));
tasks.Add(Task.Run(() => Race("长颈鹿")));
Task.WaitAny(tasks.ToArray());//会阻塞当前线程,等待某一个任务完成,才进入下一行,会卡界面
Console.WriteLine("第一名产生");
Task.WaitAll(tasks.ToArray());//阻塞当前线程,等待任务全部完成,会卡界面
}
#endregion
//赛跑
public void Race(string animal)
{
Console.WriteLine($"{animal}赛号为{Thread.CurrentThread.ManagedThreadId.ToString("00")},已就位");
long lResult = 0;
for (int i = 0; i < 1000000000; i++)
{
lResult += i;
}
Console.WriteLine($"{animal}到达终点");
}
运行结果如下图,那么恭喜乌龟了
值得一提的是 WaitAny, WaitAll也提供了超时等待的Api 如Task.WaitAll(tasks.ToArray(), 1000); 最多等待1s,超时就不等了,-1为无限等待
还有一点就是,WaitAny, WaitAll卡的是运行线程,如果在启动一个Task将WaitAny, WaitAll方法包裹起来,就不会卡界面了,像这样
Task.Run(()={
Task.WaitAny(tasks.ToArray());
})
WhenAny和WhenAll与WaitAny和WaitAll最大的区别在与一个阻塞主线程,一个不阻塞主线程,那么在waitAny和WhenAll完成之后的动作应该怎么写呢
Task.WhenAny(tasks.ToArray()).ContinueWith(t =>
{
Console.WriteLine("第一名产生");
});//不阻塞当前线程
Task.WhenAll(tasks.ToArray()).ContinueWith(t =>
{
Console.WriteLine("比赛结束");
});//不阻塞当前线程
用到了ContinueWith来实现,效果如下图
好吧,再次恭喜乌龟先生又一次拿到了冠军
因为WhenAny,WhenAll 它的返回值是一个Task,所以当某些时候需要调整执行顺序时,将方法加入TaskList中,再用WaitAny,WaitAll即可
延迟,和Thread有点像,但不一样
下面是Thread 2秒钟
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
Thread.Sleep(2000);
stopwatch.Stop();
Console.WriteLine(stopwatch.ElapsedMilliseconds);
}
运行结果:
下面是delay
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
Task.Delay(2000).ContinueWith(t =>
{
stopwatch.Stop();
Console.WriteLine(stopwatch.ElapsedMilliseconds);
});
运行结果:
通过这两次对比,不难看出,Thread会卡住当前线程,delay不卡线程,只是可以等待一些时间,再去完成一些事情
Console.WriteLine($"---------开始Parallel编程,线程id{Thread.CurrentThread.ManagedThreadId.ToString("00")}---------");
Parallel.Invoke(() => { Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString("00")); }
, () => { Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString("00")); }
, () => { Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString("00")); });
Console.WriteLine($"---------结束Parallel编程{Thread.CurrentThread.ManagedThreadId.ToString("00")}---------");
通过结果我们发现主线程参与了计算,算是节约了一个线程吧
还有遍历方法如下
Parallel.For(0, 5, i => Race("兔子" + i.ToString()));
有for,肯定有foreach
Parallel.ForEach(new int[] { 1, 2, 3, 4, 5 }, i => Race("兔子" + i.ToString()));
Parallel还有一个重要方法是可以控制并发数量
ParallelOptions options = new ParallelOptions();
options.MaxDegreeOfParallelism = 3;
Parallel.For(0, 10, options, i => Race("兔子" + i.ToString()));
运行结果为:
通过运行结果,可以看到程序始终只有3个线程在跑
写完!荆轲刺秦王