C#异步多线程之TASK

论坛 期权论坛 脚本     
匿名技术用户   2021-1-7 09:29   37   0

简介

TASK首次引入.net Framework 4中,Task对象通常是以异步方式执行于线程池上,是基于ThreadPool的,您可以使用 Status 属性,以及 IsCanceled,IsCompleted和 IsFaulted 属性,以确定任务的状态,Task是目前最为推崇的多线程方法

Task的启动方式

//常规启动

Task.Run(() => DoSomeThing());

//也可以用其构造函数启动

new Task(() => DoSomeThing()).Start();

//工厂方式启动

Task.Factory.StartNew(() => DoSomeThing());

以上几种启动方式没有什么优劣差别

waitAny waitAll

#region waitAny waitAll

{

//动物界举办了第二届赛跑比赛,参赛的有兔子,乌龟,老虎,大象,长颈鹿

Console.WriteLine("动物界举办了第二届赛跑比赛,参赛的有兔子,乌龟,老虎,大象,长颈鹿");

List<Task> tasks = new List<Task>();

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

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即可

Delay

延迟,和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不卡线程,只是可以等待一些时间,再去完成一些事情

并行编程(Parallel)

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个线程在跑

写完!荆轲刺秦王

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:7942463
帖子:1588486
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP