【C# Task】开篇
概览
在学task类之前必须学习线程的知识。
以下是task命名空间的类的结构图
1、2种任务类型: 有返回值task
2、2座任务工厂 TaskFactory/TaskFactory
3、2种
4、3种类型的
5、
6、8个
7、
8、取消任务 CanellationTokenSource
9、任务并行
10、异步任务 async/await
创建Task
任务的初始化配置 :
1、构造函数new Task 创建任务
- Task(Action)
- Task(Action, CancellationToken)
- Task(Action, TaskCreationOptions)
- Task(Action
- Task(Action, CancellationToken, TaskCreationOptions)
- Task(Action
- Task(Action
- Task(Action
(1)默认start()方法调用TaskScheduler.Current 任务调度器。如果要指定调度器请使用Start(TaskScheduler)。TaskScheduler.Current 是task默认的任务调度器,因为任务内部会创建子任务,如果是ui的调度器 就利用消息机制,如果是线程池就用线程池任务调度器。
Task()创建的任务处于 Created状态,必须调用Start运行任务后任务状态才能变成WaitingToRun。
//相当于:Task.Factory.StartNew(A, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); task状态为WaitingForRun。
而默认的TaskScheduler采用的是.NET线程池ThreadPool,它主要面向的是细粒度的小任务,其执行时间通常在毫秒级。
2、Task.Run方式创建task
Task.Run已经完成配置,直接使用。它的默认配置是:Task.Factory.StartNew(someAction , CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
TaskFactory.StartNew(工厂创建)/Task.Run() 方法是用于创建和计划计算的任务的首选的机制。该创建的任务处于WaitingToRun状态(注意:异步任务总是 WaitingForActivation)。Task.Run()轻型的TaskFactory.StartNew。
注意:TPL ( Task-Parallel-Library )、Task类(class)和 TaskStatus枚举是在 async-await 关键字引入之前就已经存在了。
async-await 引入后任务会多一种状态,但是又不能去修改之前发布的TaskStatus枚举。所以结合异步的基本处于等待状态的特性。
就将异步任务的运行状态表示为WaitingForActivation状态。
var task1 = new Task(() => { //相当于:Task.Factory.StartNew(A, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); 状态为WaitingForRun。 }); task1.Start(); ///异步总是 WaitingForActivation //详细解释 https://stackoverflow.com/questions/20830998/async-always-waitingforactivation var t = Task.Run(async delegate { await Task.Delay(5000); return 42; }); Console.WriteLine(t.Status);///异步总是 WaitingForActivation t.Wait(); Console.WriteLine(t.Status); Console.WriteLine("Task t Status: {0}, Result: {1}", t.Status, t.Result);
3、Task.ContinueWith 创建后续任务
这种方式创建的任务,依附于主任务。这种方式创建的任务处于WaitingForActivation状态。Task.ContinueWith()内部用默认的TaskScheduler.Current,触发显示的指定任务计划否则都用默认的。
Task main = Task.Run(
() => {
Console.WriteLine($"{Environment.CurrentManagedThreadId} running");
Thread.Sleep(2000);
}
) ;
Task task1=main.ContinueWith(ts => Console.WriteLine("sub task ")) ;
Console.WriteLine(task1.Status);
//输出 WaitingForActivation
4、工厂方式创建Task
(1)、有两座工厂一个是泛型工厂TaskFactory
用工厂模式创建任务第一步就是配置工厂设置,两座工厂的配置都是一样的,也可采用默认的设置。
TaskFactory() 采用默认模式工厂设置。默认工厂设置TaskCreationOptions.None,TaskContinuationOptions.None ,CancellationToken.None, TaskScheduler.Scheduler=null 创建任务时候使用TaskScheduler.Current。
TaskFactory(CancellationToken)单独设定一个CancellationToken,其他配置采用默认工厂设置
TaskFactory(TaskScheduler) 单独设定一个任务调度器,其他配置采用默认工厂设置
TaskFactory(TaskCreationOptions, TaskContinuationOptions),其他配置采用默认工厂设置
TaskFactory(CancellationToken, TaskCreationOptions, TaskContinuationOptions, TaskScheduler)全部重新设置
(2)、利用默认配置或者重新配置过的设置,创建任务。
(3)、Task.Factory.StartNew() 采用的是 默认的工厂设置。
1、var task = Task.Run(() => Console.WriteLine("cancelled")); 2、 var task2 = Task.Factory.StartNew(() => { //TODO you code }); 3、var t = Task<int>.Run(() => { // Just loop. int max = 1000000; int ctr = 0; for (ctr = 0; ctr <= max; ctr++) { if (ctr == max / 2 && DateTime.Now.Hour <= 12) { ctr++; break; } } return ctr; }); Console.WriteLine("Finished {0:N0} iterations.", t.Result);
Task的任务控制
| 老的 | 新的 | 描述 |
|---|---|---|
| task.Wait | await task | 等待/等待任务完成 |
| task.Result | await task | 获取完成任务的结果 |
| Task.WaitAny | await Task.WhenAny | 等待/等待一组任务中的一个完成 |
| Task.WaitAll | await Task.WhenAll | 等待/等待一组任务中的每一个完成 |
| Thread.Sleep | await Task.Delay | 等待/等待一段时间 |
| Task constructor | Task.Run or TaskFactory.StartNew | 创建基于代码的任务 |
Wait 阻塞
WaitAll 返回bool
WaitAny 返回任务数组的第一完成任务索引(包括取消、错误、完成)
WhenAll 返回数组或者集合任务结果(包括取消、错误、完成)
WhenAny 返回数组或者集合任务第一完成任务(包括取消、错误、完成)
Run/start 运行任务
Run():静态方法线程池线程运行
RunSynchronously()/RunSynchronously(TaskScheduler):实例方法当前线程运行,可以传入任务调度器,或者采用默认线程池任务调度器.通过调用 RunSynchronously() 方法执行的任务必须是 Task 或 Task
Start ()/Start(TaskScheduler):实例方法 运行任务,可以传入任务调度器,或者采用默认线程池任务调度器。通过调用Start()方法执行的任务必须是 Task 或 Task
//在当前线程运行任务 Console.WriteLine("app threadID:" + Environment.CurrentManagedThreadId); Task tasksync = new Task(() => Console.WriteLine($"taskID:{Task.CurrentId} taskThreadID:{Environment.CurrentManagedThreadId}")) ; tasksync.RunSynchronously(); //采用默认的线程池线程 Task task = new(()=> Console.WriteLine($"taskID:{Task.CurrentId} taskThreadID:{Environment.CurrentManagedThreadId}")); task.Start(); //采用默认的线程池线程 Task.Run(() => Console.WriteLine($"taskID:{Task.CurrentId} taskThreadID:{Environment.CurrentManagedThreadId}")); Console.Read();
Task.Delay延迟任务执行
Delay(Int32, CancellationToken) 创建一个在指定的毫秒数后完成的可取消任务。
Delay(TimeSpan, CancellationToken) 创建一个在指定的时间间隔后完成的可取消任务。
Delay(Int32) 创建一个在指定的毫秒数后完成的任务。
Delay(TimeSpan) 创建一个在指定的时间间隔后完成的任务。
1.Task.Delay实质是创建一个任务,再任务中开启一个定时间,然后延时指定的时间
2.Task.Delay不和await一起使用情况,当代码遇到Task.Delay一句时,创建了了一个新的任务去执行延时去了,当前代码继续往下执行,这情况task.wait 是不包含Task.Delay的时间的。
3.Task.Delay和await一起使用,当代码遇到await Task.Delay时候,当前线程要等该行代码执行完成后,再继续执行后面的代码
//同步阻塞 Task task = new( ()=> { Task.Delay(5000).Wait();//同步阻塞 只有直接到了,才会继续执行后面的代码。
//不阻塞 创建了一个新的任务去执行延时去了,当前代码继续往下执行
Task.Delay(5000); Console.WriteLine($"taskID:{Task.CurrentId} taskThreadID:{Environment.CurrentManagedThreadId}"); }); //异步阻塞 Task task2 = new(async () => { await Task.Delay(5000) ; Console.WriteLine($"taskID:{Task.CurrentId} taskThreadID:{Environment.CurrentManagedThreadId}"); // 不会等待异步或者同步的Task.Delay方法,也可说Wait没达到预期效果。 }); task.Start();//task.Wait();达到预期效果 task2.Start();//task.Wait();不能达到预期效果 Console.ReadLine();
Task.Delay(),Task.Delay是基于计时器的等待机制,使用系统计时器,系统定时器的滴答速度约为16ms(windows 为15ms)。这意味着,如果参数msecondsdelay小于系统时钟的分辨率(在Windows系统上大约为15毫秒),那么时间延迟将大约等于系统时钟的分辨率。如果查看源代码,您会找到对Timer类的引用,该类负责延迟。另一方面,Thread.Sleep实际上使当前线程进入休眠状态,这样你只是阻塞并浪费一个线程。在异步编程模型中,如果您希望在延迟一段时间后发生某些事情(延续),则应始终使用Task.Delay()。await Task.Delay()释放线程做其他事情,直到计时器到期,100%清除。
使用Task.Delay,您始终可以提供取消令牌并优雅地将其删除。这就是我选择Task.Delay的一个原因。
异步代码的一个主要优点是允许一个线程同时处理多个任务,避免阻塞调用。这避免了对大量单个线程的需求,并允许线程池一次为多个请求提供服务。但是,鉴于异步代码通常在线程池上运行,不必要地使用Thread.Sleep()阻塞单个线程会占用整个线程,否则可能会在其他地方使用。如果使用Thread.Sleep()运行许多任务,则很有可能耗尽所有线程池线程并严重阻碍性能。在线程池线程中运行Thread.Sleep()是一个不好的做法。
//使用方式一,在异步中使用 public static Task ShortDelay(TimeSpan delay) { await Task.Delay(delay); Console.WriteLine(string.Format("延迟{0}", delay)); } //使用方式二,在同步代码中使用,没任何效果 Task.Factory.StartNew(() => { Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + " ====== 开始Delay()"); for (int i = 101; i < 120; i++) { Task ass= Task.Delay(5000); ass.ContinueWith(t => Console.WriteLine("fdfdf")); Console.WriteLine(ass.Id); Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + " ===Delay=== " + i); Task.Delay(100);//fang'hui } Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + " ====== 结束Delay()"); });
C#中的Task.Delay()和Thread.Sleep()
- Thread.Sleep()是同步延迟,Task.Delay()是异步延迟。
- Thread.Sleep()会阻塞线程,Task.Delay()不会。
- Thread.Sleep()不能取消,Task.Delay()可以。
- Task.Delay()实质创建一个运行给定时间的任务,Thread.Sleep()使当前线程休眠给定时间。
- 反编译Task.Delay(),基本上讲它就是个包裹在任务中的定时器。
- 4. Task.Delay() 比 Thread.Sleep() 消耗更多的资源,但是Task.Delay()可用于为方法返回Task类型;或者根据CancellationToken取消标记动态取消等待
- Task.Delay()和Thread.Sleep()最大的区别是Task.Delay()旨在异步运行,在同步代码中使用Task.Delay()是没有意义的;在异步代码中使用Thread.Sleep()是一个非常糟糕的主意。通常使用await关键字调用Task.Delay()。
- 我的理解:Task.Delay(),async/await和CancellationTokenSource组合起来使用可以实现可控制的异步延迟
同步等待任务,会阻塞线程
wait
等待一个任务完成,都是实例方法
void Wait()
无限等待 Task 完成执行过程。
【异常】 1、任务被释放 2、任务被取消 3、任务内部抛出异常
bool Wait(Int32)
【参数】Int32 等待 Task 在指定的毫秒数内完成执行,或为 Infinite (-1),表示无限期等待。 超时返回false
【异常】1、任务被释放 2、参数Int32超出范围int.MaxValue>Time>=-1 3、任务内部抛出异常 4、任务被取消
bool Wait(Int32, CancellationToken)
【参数】Int32 等待 Task 完成执行过程。 如果在任务完成之前超时间隔结束或取消标记已取消,等待将终止,或为 Infinite (-1),表示无限期等待。。超时返回false
【异常】1、任务被释放 2、任务被取消 3、任务内部抛出异常 4、Wait(CancellationToken) CancellationToken被取消 5、参数Int32超出范围int.MaxValue>Time>=-1
bool Wait(TimeSpan)
【参数】TimeSpan在指定的时间间隔内完成任务才会返回true,否则放回false。表示等待的毫秒数的TimeSpan,或者表示-1毫秒的TimeSpan,表示无限期等待。内部转化成Wait(Int32, CancellationToken)等待 。超时返回false
【异常】1、任务被释放 2、任务被取消 3、任务内部抛出异常 4、参数TimeSpan超出范围int.MaxValue>Time>=-1
void Wait(CancellationToken)
【参数】CancellationTokenTask 完成执行过程 无限等待直到取消 。
【异常】1、任务被释放 2、任务被取消 3、任务内部抛出异常 4、Wait(CancellationToken) CancellationToken被取消
void Wait() 案例
CancellationTokenSource cts = new CancellationTokenSource(); CancellationToken ct = cts.Token; Task task4 = Task.Run( () => { Console.WriteLine("任务4开始"); while (true) { if (ct.IsCancellationRequested) { ct.ThrowIfCancellationRequested(); } Task.Delay(2000).Wait(); } }, cts.Token ); cts.Cancel(); try { // 1、任务被释放 2、任务被取消 3、任务内部抛出异常 task4.Wait(); } catch (Exception ex) { Console.WriteLine(ex.Message); } Console.Read();
void Wait(CancellationToken)案例
CancellationTokenSource cts = new CancellationTokenSource(); CancellationToken ct = cts.Token; Task task4 = Task.Run( () => { Console.WriteLine("任务4开始"); while (true) { if (ct.IsCancellationRequested) { ct.ThrowIfCancellationRequested(); } Task.Delay(2000).Wait(); } } ); cts.Cancel(); try { // 1、任务被释放 2、任务被取消 3、任务内部抛出异常 4、Wait(CancellationToken) 触发取消 task4.Wait(ct); } catch (Exception ex) { Console.WriteLine(ex.Message); } Console.Read();
public bool Wait (int millisecondsTimeout)案例
CancellationTokenSource cts = new CancellationTokenSource(); CancellationToken ct = cts.Token; Task task4 = Task.Run( () => { Console.WriteLine("任务4开始"); while (true) { if (ct.IsCancellationRequested) { ct.ThrowIfCancellationRequested(); } Task.Delay(2000).Wait(); } },ct ); //cts.Cancel(); try { // 1、任务被释放 2、时间超出范围 3、任务内部抛出异常 4、任务被取消 task4.Wait(100);//超时返回false } catch (Exception ex) { Console.WriteLine(ex.Message); } Console.Read();
WaitAll
等待一组任务完成,都是静态方法
public static void WaitAll (params Task[] tasks)
【异常】 1、数组中 >=1任务被释放了 2、tasks数组为null 3、 tasks数组包含null元素 4、任务被取消了 5、任务内部抛出异常
public static bool WaitAll (Task[] tasks, int millisecondsTimeout)
【参数】int millisecondsTimeout 表示所有的数组中的任务在规定的 时间内完成 才返回true,否则返回false。 Infinite (-1),表示无限期等待。超时返回false
【异常】1、数组中 >=1任务被释放了 2、tasks数组为null 3、 tasks数组包含null元素 4、任务被取消了 5、任务内部抛出异常 6、参数millisecondsTimeout 超出范围int.MaxValue>Time>=-1
[System.Runtime.Versioning.UnsupportedOSPlatform("browser")]
public static void WaitAll (Task[] tasks, CancellationToken cancellationToken)
【特性】UnsupportedOSPlatform("browser"):表示该api不被浏览器支持。
【异常】 1、数组中 >=1任务被释放了 2、tasks数组为null 3、 tasks数组包含null元素 4、任务被取消了 5、任务内部抛出异常 6、WaitAll(arrtasks, ct)方法ct 取消
public static bool WaitAll ( Task[] tasks, TimeSpan timeout)
【参数】TimeSpan timeout:在时间间隔内等待(例如:TimeSpan.FromMilliseconds(1000) 表示 1s) 或者表示-1毫秒的TimeSpan,表示无限期等待。 内部也是转化成public static bool WaitAll (Task[] tasks, int millisecondsTimeout)。超时 返回后false。
【异常】 1、数组中 >=1任务被释放了 2、tasks数组为null 3、 tasks数组包含null元素 4、任务被取消了 5、任务内部抛出异常 6、参数timeout 超出范围int.MaxValue>Time>=-1
[System.Runtime.Versioning.UnsupportedOSPlatform("browser")]
public static bool WaitAll (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken);
【特性】UnsupportedOSPlatform("browser"):表示该api不被浏览器支持。
【参数】int millisecondsTimeout 所有的数组中的任务在规定的 时间内完成 才返回true,否则返回false。 Infinite (-1),表示无限期等待。
【异常】 1、数组中 >=1任务被释放了 2、tasks数组为null 3、 tasks数组包含null元素 4、任务被取消了 5、任务内部抛出异常 6、参数millisecondsTimeout超出范围int.MaxValue>Time>=-1 7、参数cancellationToken取消
public static void WaitAll (params Task[] tasks)案例
CancellationTokenSource cts = new CancellationTokenSource(); CancellationToken ct = cts.Token; Task task1 = Task.Run(() => { Console.WriteLine("任务1开始"); Task.Delay(3000).Wait(); Console.WriteLine("任务1完成"); }); Task task2 = Task.Run(() => { Console.WriteLine("任务2开始"); Task.Delay(2000).Wait(); Console.WriteLine("任务2完成"); }); Task task3 = Task.Run(() => { Console.WriteLine("任务3开始"); Task.Delay(10000).Wait(); Console.WriteLine("任务3完成"); }); Task task4 = Task.Run( () => { Console.WriteLine("任务4开始"); while (true) { if (ct.IsCancellationRequested) { ct.ThrowIfCancellationRequested(); } Task.Delay(2000).Wait(); } }, cts.Token ); cts.Cancel(); Task[] arrtasks = new[] { task1, task2, task4 }; try { // 捕获异常 1、数组中 >=1任务被释放了 2、tasks数组为null 3、 tasks数组包含null元素 4、任务被取消了 5、任务内部抛出异常 bool dd =Task.WaitAll(arrtasks);//写法二 Task.WaitAll(task1, task2, task3); // Console.WriteLine(dd); }catch (Exception ex) { } Console.Read();
public static bool WaitAll (Task[] tasks, int millisecondsTimeout)案例
//其他代码同上 try { // 捕获异常 1、数组中 >=1任务被释放了 2、tasks数组为null 3、 tasks数组包含null元素 4、任务被取消了 5、任务内部抛出异常 6、时间超出范围 bool waitStatus =Task.WaitAll(arrtasks, 20000);//wait超时 返回后false。 Console.WriteLine(waitStatus); }catch (Exception ex) { }
public static void WaitAll (Task[] tasks, CancellationToken cancellationToken)案例
//其他代码同上 try { // 捕获异常 1、数组中 >=1任务被释放了 2、tasks数组为null 3、 tasks数组包含null元素 // 4、任务被取消了 5、任务内部抛出异常 6、WaitAll(arrtasks, ct)方法ct 取消 Task.WaitAll(arrtasks, ct); } catch (Exception ex) { }
public static bool WaitAll ( Task[] tasks, TimeSpan timeout)案例
//其他代码同上 Task[] arrtasks = new[] { task1, task2, task4 }; TimeSpan ts = DateTime.Now - DateTime.Now.AddSeconds(-1); try { // 捕获异常 1、数组中 >=1任务被释放了 2、tasks数组为null 3、 tasks数组包含null元素 // 4、任务被取消了 5、任务内部抛出异常 6、时间超出范围X<-1 或 X>maxTime bool outime= Task.WaitAll(arrtasks, ts);// Task.WaitAll(arrtasks, TimeSpan.FromMilliseconds(5000));//表示5s // 超时 返回后false。 Console.WriteLine(outime ); } catch (Exception ex) { }
public static bool WaitAll (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)案例
//其他代码同上 //cts.Cancel(); Task[] arrtasks = new[] { task1, task2, task4 }; TimeSpan ts = DateTime.Now - DateTime.Now.AddSeconds(-1); try { // 捕获异常 1、数组中 >=1任务被释放了 2、tasks数组为null 3、 tasks数组包含null元素 // 4、任务被取消了 5、任务内部抛出异常 6、时间超出范围X<-1 或 X>maxTime 7、WaitAll(arrtasks,1000, ct)方法ct 取消 bool outime = Task.WaitAll(arrtasks, 1000,ct);// Task.WaitAll(arrtasks, TimeSpan.FromMilliseconds(5000));//表示5s // 超时 返回后false。 Console.WriteLine(outime ); } catch (Exception ex) { } Console.Read();
WaitAny
等等待一组任务中 任意一个完成 返回值是数组索引。都是静态方法
static int WaitAny(Task[], TimeSpan)
【说明】等待任何提供的 Task 对象在指定的时间间隔内完成执行。任务成功返回数组索引
【异常】1、数组中的任务被释放 2、tasks数组是null 3、tasks数组包含空元素 4、WaitAny(Task[], Int32)Int32 超出范围int.MaxValue>Time>=-1
static int WaitAny(Task[], Int32, CancellationToken)
【说明】 等待提供的任何 Task 对象在指定的毫秒数内完成执行,或等到取消标记取消。Int32表示Task 对象在指定的毫秒数内完成执行,或表示 -1 毫秒(无限期等待) 。任务成功返回数组索引
【异常】【异常】1、数组中的任务被释放 2、tasks数组是null 3、tasks数组包含空元素 4、WaitAny(Task[], Int32)Int32 超出范围int.MaxValue>Time>=-1 5、参数CancellationToken 取消
static int WaitAny(Task[], CancellationToken)
【说明】 等待提供的任何 Task 对象完成执行过程(除非取消等待)。任务成功返回数组索引
【异常】1、数组中的任务被释放 2、tasks数组是null 3、tasks数组包含空元素 4、参数CancellationToken 取消
static int WaitAny(Task[], Int32)
【说明】等待任何提供的 Task 对象在指定的毫秒数内完成执行或表示 -1 毫秒(无限期等待)。任务成功返回数组索引
【异常】1、数组中的任务被释放 2、tasks数组是null 3、tasks数组包含空元素 4、WaitAny(Task[], Int32)Int32 超出范围int.MaxValue>Time>=-1
static int WaitAny(Task[])
【说明】等待提供的任一 Task 对象完成执行过程。任务成功返回数组索引
【异常】1、数组中的任务被释放 2、tasks数组是null 3、tasks数组包含空元素
static int WaitAny(Task[], Int32)案例,其他api就不举子了,都一样
CancellationTokenSource cts = new CancellationTokenSource(); CancellationToken ct = cts.Token; Task task1 = Task.Run(() => { Console.WriteLine("任务1开始"); Task.Delay(3000).Wait(); Console.WriteLine("任务1完成"); }); Task task2 = Task.Run(() => { Console.WriteLine("任务2开始"); Task.Delay(2000).Wait(); Console.WriteLine("任务2完成"); }); Task task3 = Task.Run(() => { Console.WriteLine("任务3开始"); Task.Delay(10000).Wait(); Console.WriteLine("任务3完成"); }); Task task4 = Task.Run( () => { Console.WriteLine("任务4开始"); while (true) { if (ct.IsCancellationRequested) { ct.ThrowIfCancellationRequested(); } Task.Delay(2000).Wait(); } }, cts.Token ); //cts.Cancel(); Task[] arrtasks = new[] { task1, task2, task4 }; try { // 捕获异常 1、数组中的任务被释放 2、tasks数组是null 3、tasks数组包含空元素 4、WaitAny(Task[], Int32)Int32 超出范围int.MaxValue>Time>=-1 int index = Task.WaitAny(arrtasks,20000);// Console.WriteLine("数组索引"+index); } catch (Exception ex) { } Console.Read();
异步等待任务,不会阻塞线程
WaitAsync
异步等待,实例方法,未提供int32类型Api但是可以用TimeSpan.FromMilliseconds(5000)来实现int32类型的等待。
Task WaitAsync(TimeSpan, CancellationToken) 获取一个任务,该任务将在此任务完成时、指定的超时超时时或指定的CancellationToken被请求取消时完成。
CancellationTokenSource CancellationTokenSource=new CancellationTokenSource(); CancellationTokenSource.Cancel(); Task<string> task1 = Task.Run(() => { Console.WriteLine("任务1开始"); Task.Delay(4000).Wait(); Console.WriteLine("任务1完成"); return "task1complet"; }); //异步等待2或者接收到取消信号,然后输出等待的状态 task1.WaitAsync(TimeSpan.FromMilliseconds(2000),CancellationTokenSource.Token).ContinueWith((t) => Console.WriteLine("等待任务的状态"+t.Status)); // 时间间隔内等待,等待5秒钟 //TimeSpan ts = DateTime.Now - DateTime.Now.AddSeconds(-5); //task1.WaitAsync(TimeSpan.FromMilliseconds(ts)).ContinueWith((t) => Console.WriteLine("等待任务的状态" + t.Status)); Console.WriteLine("任务1的状态" + task1.Status); Console.Read(); /*输出 任务1开始 任务1的状态Running 等待任务的状态Canceled 任务1完成 */
Task WaitAsync(TimeSpan) 返回一个任务A,该任务将在B任务完成后 或指定超时超时时完成的任务。
Task<string> task1 = Task.Run(() => { Console.WriteLine("任务1开始"); Task.Delay(4000).Wait(); Console.WriteLine("任务1完成"); return "task1complet"; }); //异步等待2s,然后输出等待的状态 未提供int32类型Api但是可以用TimeSpan.FromMilliseconds(5000)来实现int32类型的等待。 task1.WaitAsync(TimeSpan.FromMilliseconds(2000)).ContinueWith((t) => Console.WriteLine("等待任务的状态"+t.Status)); // 时间间隔内等待,等待5秒钟 //TimeSpan ts = DateTime.Now - DateTime.Now.AddSeconds(-5); //task1.WaitAsync(TimeSpan.FromMilliseconds(ts)).ContinueWith((t) => Console.WriteLine("等待任务的状态" + t.Status)); Console.WriteLine("任务1的状态" + task1.Status); Console.Read(); /*输出 任务1开始 任务1的状态Running 等待任务的状态Faulted 任务1完成 */
Task WaitAsync(CancellationToken) 返回一个任务A,该任务将在B任务完成后完成
WhenAll
等待一组任务完成,返回值是task,都是静态方法
static WhenAll(IEnumerable
创建一个任务,该任务将在可枚举集合中的所有task对象都完成时完成。
调用WhenAll(IEnumerable
如果提供的任何任务在fault状态下完成,返回的任务也将在fault状态下完成,其中其异常将包含来自每个提供的任务的未包装异常集的聚合。
如果提供的任务中没有一个出错,但至少有一个被取消,则返回的任务将以取消状态结束。
如果没有任务出错,也没有任务被取消,则生成的任务将以RanToCompletion状态结束。
如果提供的数组/enumerable不包含任务,返回的任务将在返回给调用者之前立即转换到RanToCompletion状态。
static WhenAll(paramsTask[])
创建一个任务,该任务将在数组中的所有task对象都完成时完成。
调用WhenAll(Task[])方法不会阻塞调用线程。
如果提供的任何任务在fault状态下完成,返回的任务也将在fault状态下完成,其中其异常将包含来自每个提供的任务的未包装异常集的聚合。
如果提供的任务中没有一个出错,但至少有一个被取消,则返回的任务将以取消状态结束。
如果没有任务出错,也没有任务被取消,则生成的任务将以RanToCompletion状态结束。
如果提供的数组/enumerable不包含任务,返回的任务将在返回给调用者之前立即转换到RanToCompletion状态。
static Task
创建一个任务,该任务将在可枚举集合中的所有task 对象都完成时完成。
调用WhenAll(IEnumerable>)方法不会阻塞调用线程。但是,对返回的Result属性的调用会阻塞调用线程。
如果提供的任何任务在fault状态下完成,返回的任务也将在fault状态下完成,其中其异常将包含来自每个提供的任务的未包装异常集的聚合。
如果提供的任务中没有一个出错,但至少有一个被取消,则返回的任务将以取消状态结束。
如果没有任务出错,也没有任务被取消,则生成的任务将以RanToCompletion状态结束。任务<
TResult
>。返回任务的Result属性将被设置为一个数组,其中包含所提供任务的所有结果,顺序与提供的顺序相同(例如,如果输入任务数组包含t1,
t2, t3,则输出任务的task 。Result属性将返回一个TResult[],其中arr[0] == t1。结果,arr[1] ==
t2。和arr[2] == t3.Result)。
如果tasks参数不包含任务,返回的任务将在返回给调用者之前立即转换到RanToCompletion状态。返回的TResult[]将是一个包含0个元素的数组。
static TaskparamsTask
创建一个任务,该任务将在数组中的所有task 对象都完成时完成。
以上案例如下:
static WhenAll(IEnumerable
var tasklist=new List(); Task task1 = Task.Run(() => { Console.WriteLine("任务1开始"); Task.Delay(3000).Wait(); Console.WriteLine("任务1完成"); }); Task task2 = Task.Run(() => { Console.WriteLine("任务2开始"); Task.Delay(2000).Wait(); Console.WriteLine("任务2完成"); }); Task task3 = Task.Run(() => { Console.WriteLine("任务3开始") ; Task.Delay(10000).Wait(); Console.WriteLine("任务3完成"); }); tasklist.Add(task1); tasklist.Add(task2); tasklist.Add(task3); Task taskswait = Task.WhenAll(tasklist); try { //等待期间可能发送错误、取消等 所有要捕获异常 taskswait.Wait(); } catch (OperationCanceledException ex) { Console.WriteLine(ex.Message); }
注意
调用WhenAll(IEnumerable
如果提供的任何任务在fault状态下完成,返回的任务也将在fault状态下完成,其中其异常将包含来自每个提供的任务的未包装异常集的聚合。
如果提供的任务中没有一个出错,但至少有一个被取消,则返回的任务将以取消状态结束。
如果没有任务出错,也没有任务被取消,则生成的任务将以RanToCompletion状态结束。
如果提供的数组/enumerable不包含任务,返回的任务将在返回给调用者之前立即转换到RanToCompletion状态。
static WhenAll(paramsTask[]) 案例
Task task1 = Task.Run(() => { Console.WriteLine("任务1开始"); Task.Delay(3000).Wait(); Console.WriteLine("任务1完成"); });
Task task2 = Task.Run(() => { Console.WriteLine("任务2开始"); Task.Delay(2000).Wait(); Console.WriteLine("任务2完成"); });
Task task3 = Task.Run(() => { Console.WriteLine("任务3开始") ; Task.Delay(10000).Wait(); Console.WriteLine("任务3完成"); });
Task[] arrtasks = new[] { task1 , task2 , task3 };
Task taskswait= Task.WhenAll(arrtasks);
try
{
//等待期间 任务可能取消、发生异常等,所有要捕获异常
taskswait.Wait();
}
catch (OperationCanceledException ex)
{
Console.WriteLine(ex.Message);
}
Console.Read();
注意
调用WhenAll(Task[])方法不会阻塞调用线程。
如果提供的任何任务在fault状态下完成,返回的任务也将在fault状态下完成,其中其异常将包含来自每个提供的任务的未包装异常集的聚合。
如果提供的任务中没有一个出错,但至少有一个被取消,则返回的任务将以取消状态结束。
如果没有任务出错,也没有任务被取消,则生成的任务将以RanToCompletion状态结束。
如果提供的数组/enumerable不包含任务,返回的任务将在返回给调用者之前立即转换到RanToCompletion状态。
WhenAll
var tasklist=new Liststring>>(); Task<string> task1 = Task<string>.Run(() => { Console.WriteLine("任务1开始"); Task.Delay(3000).Wait(); Console.WriteLine("任务1完成"); return "task1complet"; }); Task<string> task2 = Task<string>.Run(() => { Console.WriteLine("任务2开始"); Task.Delay(2000).Wait(); Console.WriteLine("任务2完成"); return "task2complet"; }); Task<string> task3 = Task<string>.Run(() => { Console.WriteLine("任务3开始") ; Task.Delay(10000).Wait(); Console.WriteLine("任务3完成"); return "task3complet"; }); tasklist.Add(task1); tasklist.Add(task2); tasklist.Add(task3); Task<string[]>taskswait = Task<string>.WhenAll<string>(tasklist); try { //等待期间可能发送错误、取消等 所有要捕获异常 taskswait.Wait(); } catch (OperationCanceledException ex) { Console.WriteLine(ex.Message); } if (taskswait.Status == TaskStatus.RanToCompletion) { foreach (var item in taskswait.Result) { Console.WriteLine(item); } } else { } Console.Read();
注意
调用WhenAll(IEnumerable>)方法不会阻塞调用线程。但是,对返回的Result属性的调用会阻塞调用线程。
如果提供的任何任务在fault状态下完成,返回的任务也将在fault状态下完成,其中其异常将包含来自每个提供的任务的未包装异常集的聚合。
如果提供的任务中没有一个出错,但至少有一个被取消,则返回的任务将以取消状态结束。
如果没有任务出错,也没有任务被取消,则生成的任务将以RanToCompletion状态结束。任务< TResult >。返回任务的Result属性将被设置为一个数组,其中包含所提供任务的所有结果,顺序与提供的顺序相同(例如,如果输入任务数组包含t1, t2, t3,则输出任务的task 。Result属性将返回一个TResult[],其中arr[0] == t1。结果,arr[1] == t2。和arr[2] == t3.Result)。
如果tasks参数不包含任务,返回的任务将在返回给调用者之前立即转换到RanToCompletion状态。返回的TResult[]将是一个包含0个元素的数组。
参考案例:https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.whenall?view=net-6.0#system-threading-tasks-task-whenall-1(system-threading-tasks-task((-0))())
WhenAny
等待一组任务完成,返回值是Task
static Task
创建一个任务,该任务将在任何提供的任务完成时完成。
当提供的任何任务完成时,返回的任务将完成。返回的任务将总是以RanToCompletion状态结束,其Result被设置为第一个要完成的任务。即使要完成的第一个任务以“已取消”或“已故障”状态结束,也同样如此。
static Task
创建一个任务,该任务将在任何提供的任务完成时完成。
当提供的任何任务完成时,返回的任务将完成。返回的任务将总是以RanToCompletion状态结束,其Result被设置为第一个要完成的任务。即使要完成的第一个任务以“已取消”或“已故障”状态结束,也同样如此。
static Task
创建一个任务,该任务将在任何提供的任务完成时完成。
当提供的任何任务完成时,返回的任务将完成。返回的任务将总是以RanToCompletion状态结束,其Result被设置为第一个要完成的任务。即使要完成的第一个任务以“已取消”或“故障”状态结束,结果值也为真。
static Task
创建一个任务,该任务将在任何提供的任务完成时完成。
当提供的任何任务完成时,返回的任务将完成。返回的任务将总是以RanToCompletion状态结束,其Result被设置为第一个要完成的任务。即使要完成的第一个任务以“已取消”或“故障”状态结束,结果值也为真。
static Task
创建一个任务,该任务将在两个任务中的任何一个任务完成时完成。
当提供的任何任务完成时,返回的任务将完成。返回的任务将总是以RanToCompletion状态结束,其Result被设置为第一个要完成的任务。即使要完成的第一个任务以“已取消”或“已故障”状态结束,也同样如此。
static Task
var tasklist=new Liststring>>(); Task<string> task1 = Task.Run(() => { Console.WriteLine("任务1开始"); Task.Delay(3000).Wait(); Console.WriteLine("任务1完成"); return "task1complet"; }); Task<string> task2 = Task.Run(() => { Console.WriteLine("任务2开始 准备返回的任务ID:"+ Task.CurrentId); Task.Delay(2000).Wait(); Console.WriteLine("任务2完成"); return "task2complet CurrentId"; }); Task<string> task3 = Task.Run(() => { Console.WriteLine("任务3开始") ; Task.Delay(4000).Wait(); Console.WriteLine("任务3完成"); return "task3complet"; }); tasklist.Add(task1); tasklist.Add(task2); tasklist.Add(task3); Task string>> taskswait = Task.WhenAny<string>(tasklist.ToArray()); try { //等待期间可能发送错误、取消等 所有要捕获异常 taskswait.Wait(); } catch (OperationCanceledException ex) { Console.WriteLine(ex.Message); } if (taskswait.Status == TaskStatus.RanToCompletion) { Console.WriteLine("返回的任务ID:"+ taskswait.Result.Id); } else { } Console.Read();