Task是.NetFramework3.0出现的,线程是基于线程池,而后提供了丰富的API数据库
TaskFactory 提供对建立和计划 Task 对象的支持api
建立和启动异步任务缓存
一、Task task = new Task(() => ThreadPoolHelper.DoSomeThing());
task.Start();多线程
二、Task task = Task.Run(() => ThreadPoolHelper.DoSomeThing());并发
三、TaskFactory taskFactory = Task.Factory;异步
Task task = taskFactory.StartNew(() => ThreadPoolHelper.DoSomeThing());分布式
Task的线程是源于线程池 ,假如说我想控制下Task的并发数量,该怎么作?ide
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 }
运行上面的代码咱们发现几个须要注意的地方:性能
一、i的值等于100,由于异步线程的启动并不阻塞主线程;优化
二、使用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 }
使用Parallel也能够实现
Task经常使用方法
一、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 }
二、ContinueWith(Action<Task,Object>, Object)、ContinueWith(Action<Task>)、ContinueWith<TResult>(Func<Task,Object,TResult>, Object, CancellationToken, TaskContinuationOptions, TaskScheduler)、...
目标任务完成后异步执行一个延续任务
三、Wait()、Wait(CancellationToken)、Wait(Int32)、Wait(Int32, CancellationToken)、Wait(TimeSpan)
等待任务或通过指定时间为止 与Thread.Join方法、waitHandle.WaitOne方法 做用至关
四、WaitAll(Task[])、WaitAll(Task[], CancellationToken)、WaitAll(Task[], Int32)、WaitAll(Task[], Int32, CancellationToken)、WaitAll(Task[], TimeSpan)
等待全部任务对象完成执行或通过指定时间为止,或等到取消等待
五、WaitAny(Task[])、WaitAny(Task[], CancellationToken)、WaitAny(Task[], Int32)、WaitAny(Task[], Int32, CancellationToken)、WaitAny(Task[], TimeSpan)
等待全部任务对象任何一个任务对象完成执行或通过指定时间为止,或等到取消标记取消
六、WhenAll(IEnumerable<Task>)、WhenAll(Task[])、WhenAll<TResult>(IEnumerable<Task<TResult>>)、WhenAll<TResult>(Task<TResult>[])
全部任务对象都已完成时,建立一个新的任务并执行
七、WhenAny(IEnumerable<Task>)、WhenAny(Task[])、WhenAny<TResult>(IEnumerable<Task<TResult>>)、WhenAny<TResult>(Task<TResult>[])
全部任务对象任何一个任务完成就建立一个新的任务并执行
TaskFactory经常使用方法
一、ContinueWhenAll(Task[], Action<Task[]>)、ContinueWhenAll(Task[], Action<Task[]>, CancellationToken)、ContinueWhenAll(Task[], Action<Task[]>, CancellationToken, TaskContinuationOptions, TaskScheduler)、...
全部任务对象都已完成时,建立一个新的任务并执行 与Task.WhenAll方法 做用至关
二、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 }
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 }
微软文档:
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