C# Task TaskFactory 异步线程/异步任务

Task是.NetFramework3.0出现的,线程是基于线程池,然后提供了丰富的API

TaskFactory  提供对创建和计划 Task 对象的支持

创建和启动异步任务

1、Task task = new Task(() => ThreadPoolHelper.DoSomeThing());
      task.Start();

2、Task task = Task.Run(() => ThreadPoolHelper.DoSomeThing());

3、TaskFactory taskFactory = Task.Factory;

      Task task = taskFactory.StartNew(() => ThreadPoolHelper.DoSomeThing());

Task的线程是源于线程池 ,假如说我想控制下Task的并发数量,该怎么做?

 1             {
 2                 //ThreadPool.SetMaxThreads(8, 8);
 3                 //线程池是单例的,全局唯一的
 4                 //设置后,同时并发的Task只有8个;而且线程是复用的;
 5                 //全局的,请不要这样设置!!!
 6                 for (int i = 0; i < 100; i++)
 7                 {
 8                     int k = i;
 9                     Task.Run(() =>
10                     {
11                         Console.WriteLine($"This is k={k},i={i} running ThreadId={Thread.CurrentThread.ManagedThreadId.ToString("00")}");
12                         Thread.Sleep(2000);
13                     });
14                 }
15             }
View Code

运行上面的代码我们发现几个需要注意的地方:

1、i的值等于100,因为异步线程的启动并不阻塞主线程;

2、使用ThreadPool.SetMaxThreads 方法 设置后,虽然能达到效果,但是线程池是单例的,全局唯一的,这样设置会影响整个程序;

那么如何实现?

 1             {
 2                 List<Task> taskList = new List<Task>();
 3                 for (int i = 0; i < 10000; i++)
 4                 {
 5                     int k = i;
 6                     if (taskList.Count(t => t.Status != TaskStatus.RanToCompletion) >= 20)
 7                     {
 8                         Task.WaitAny(taskList.ToArray());
 9                         taskList = taskList.Where(t => t.Status != TaskStatus.RanToCompletion).ToList();
10                     }
11                     taskList.Add(Task.Run(() =>
12                     {
13                         Console.WriteLine($"This is {k} running ThreadId={Thread.CurrentThread.ManagedThreadId.ToString("00")}");
14                         Thread.Sleep(2000);
15                     }));
16                 }
17             }
View Code

使用Parallel也可以实现

Task常用方法

1、Delay(Int32)、Delay(Int32, CancellationToken)、Delay(TimeSpan)、Delay(TimeSpan, CancellationToken)

在指定的时间后执行任务

1             {
2                 Stopwatch stopwatch = new Stopwatch();
3                 stopwatch.Start();
4                 Console.WriteLine("在Delay之前");
5                 Task.Delay(2000).ContinueWith(t => { Console.WriteLine($"Delay耗时ContinueWith Start{stopwatch.ElapsedMilliseconds}"); ThreadPoolHelper.DoSomeThing(); Console.WriteLine($"Delay耗时ContinueWith End{stopwatch.ElapsedMilliseconds}"); });
6                 Console.WriteLine($"Delay耗时{stopwatch.ElapsedMilliseconds}");
7             }
View Code

2、ContinueWith(Action<Task,Object>, Object)、ContinueWith(Action<Task>)、ContinueWith<TResult>(Func<Task,Object,TResult>, Object, CancellationToken, TaskContinuationOptions, TaskScheduler)、...

目标任务完成后异步执行一个延续任务

3、Wait()、Wait(CancellationToken)、Wait(Int32)、Wait(Int32, CancellationToken)、Wait(TimeSpan)

等待任务或经过指定时间为止  与Thread.Join方法、waitHandle.WaitOne方法 作用相当

4、WaitAll(Task[])、WaitAll(Task[], CancellationToken)、WaitAll(Task[], Int32)、WaitAll(Task[], Int32, CancellationToken)、WaitAll(Task[], TimeSpan)

等待所有任务对象完成执行或经过指定时间为止,或等到取消等待

5、WaitAny(Task[])、WaitAny(Task[], CancellationToken)、WaitAny(Task[], Int32)、WaitAny(Task[], Int32, CancellationToken)、WaitAny(Task[], TimeSpan)

等待所有任务对象任何一个任务对象完成执行或经过指定时间为止,或等到取消标记取消

6、WhenAll(IEnumerable<Task>)、WhenAll(Task[])、WhenAll<TResult>(IEnumerable<Task<TResult>>)、WhenAll<TResult>(Task<TResult>[])

所有任务对象都已完成时,创建一个新的任务并执行

7、WhenAny(IEnumerable<Task>)、WhenAny(Task[])、WhenAny<TResult>(IEnumerable<Task<TResult>>)、WhenAny<TResult>(Task<TResult>[])

所有任务对象任何一个任务完成就创建一个新的任务并执行

TaskFactory常用方法

1、ContinueWhenAll(Task[], Action<Task[]>)、ContinueWhenAll(Task[], Action<Task[]>, CancellationToken)、ContinueWhenAll(Task[], Action<Task[]>, CancellationToken, TaskContinuationOptions, TaskScheduler)、...

所有任务对象都已完成时,创建一个新的任务并执行   与Task.WhenAll方法 作用相当

2、ContinueWhenAny(Task[], Action<Task>)、ContinueWhenAny<TAntecedentResult>(Task<TAntecedentResult>[], Action<Task<TAntecedentResult>>)、...

所有任务对象任何一个任务完成就创建一个新的任务并执行 与Task.WhenAny方法 作用相当

那么什么时候能用多线程? 任务能并发的时候

多线程能干嘛?提升速度/优化用户体验

网站首页:A数据库 B接口 C分布式服务 D搜索引擎,适合多线程并发,都完成后才能返回给用户,需要等待WaitAll
列表页:核心数据可能来自数据库/接口服务/分布式搜索引擎/缓存,多线程并发请求,哪个先完成就用哪个结果,其他的就不管了

现实实例

多人合作开发---多线程--提升效率/性能

 1             {
 2                 TaskFactory taskFactory = new TaskFactory();
 3                 List<Task> taskList = new List<Task>();
 4                 taskList.Add(taskFactory.StartNew(o=> Coding("A", " Portal"), "A"));
 5                 taskList.Add(taskFactory.StartNew(o=> Coding("B", "    DBA"), "B"));
 6                 taskList.Add(taskFactory.StartNew(o=> Coding("C", " Client"), "C"));
 7                 taskList.Add(taskFactory.StartNew(o=> Coding("D", "Service"), "D"));
 8                 taskList.Add(taskFactory.StartNew(o=> Coding("E", " Wechat"), "E"));
 9 
10                 //谁第一个完成,获取一个红包奖励
11                 taskFactory.ContinueWhenAny(taskList.ToArray(), t => Console.WriteLine($"{t.AsyncState}开发完成,获取个红包奖励{Thread.CurrentThread.ManagedThreadId.ToString("00")}"));
12                 //实战作业完成后,一起庆祝一下
13                 taskList.Add(taskFactory.ContinueWhenAll(taskList.ToArray(), rArray => Console.WriteLine($"开发都完成,一起庆祝一下{Thread.CurrentThread.ManagedThreadId.ToString("00")}")));
14                 //ContinueWhenAny  ContinueWhenAll 非阻塞式的回调;而且使用的线程可能是新线程,也可能是刚完成任务的线程,唯一不可能是主线程
15 
16 
17                 //阻塞当前线程,等着任意一个任务完成
18                 Task.WaitAny(taskList.ToArray());//也可以限时等待
19                 Console.WriteLine("准备环境开始部署");
20                 //需要能够等待全部线程完成任务再继续  阻塞当前线程,等着全部任务完成
21                 Task.WaitAll(taskList.ToArray());
22                 Console.WriteLine("5个模块全部完成后,集中调试");
23 
24                 //Task.WaitAny  WaitAll都是阻塞当前线程,等任务完成后执行操作
25                 //阻塞卡界面,是为了并发以及顺序控制
26             }
View Code
 1         /// <summary>
 2         /// 模拟Coding过程
 3         /// </summary>
 4         /// <param name="name"></param>
 5         /// <param name="projectName"></param>
 6         private static string Coding(string name, string projectName)
 7         {
 8             Console.WriteLine($"****************Coding Start  {name} {projectName}  {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
 9             long lResult = 0;
10             for (int i = 0; i < 1_000_000_000; i++)
11             {
12                 lResult += i;
13             }
14             Console.WriteLine($"****************Coding   End  {name} {projectName} {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} {lResult}***************");
15             return name;
16         }
View Code

微软文档:

Task:https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.tasks.task?view=netframework-4.8

TaskFactory:https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.tasks.taskfactory?view=netframework-4.8

猜你喜欢

转载自www.cnblogs.com/Dewumu/p/11821327.html