有两种启动方式:
var taskForAction = new Task(() => { //do something }); taskForAction.Start();
注:构造所有的重载并没有传入Func函数的,而且我们这个时候看线程池中活动线程数会发现改变
//打印线程池中线程活动数 PRintAvailabeWorkThreadNum(); var taskForAction = new Task(() => { //do something }); taskForAction.Start(); PrintAvailabeWorkThreadNum();
输出结果:
//打印线程池中线程活动数 PrintAvailableWorkThreadNum(); var taskForAction = Task.Run(() => Console.WriteLine("print string for Action")); var taskForFunc = Task.Run(() => "return string for Func<string>"); PrintAvailableWorkThreadNum(); //Result内部会调用Wait,所以这里不需要调 Console.WriteLine(taskForFunc.Result);
同样的,直接调用静态方法来创建一个线程,并返回当前正在执行的线程副本以供我们调用,Result只有传递进去的是Func函数才会在返回的Task中存在,如果传入的是Action函数,Result是不存在的, 这个时候线程活动数量也会改变。
已经在 【C#】线程协作式取消这章里面好好讨论过如何去取消了,如何注册回调函数等技术了.
我们有时候想在执行完一个任务以后,再开始做一个其他的任务,这个时候如果我们用Wait就会堵塞线程,如果我们用线程嵌套的方式去做,会浪费资源并损害的伸缩性。
//这样会堵塞我们的线程 Task.Run(() => { //do something }).Wait(); Task.Run(() => { //do another thing }); //虽然不会堵塞线程了,但这样会浪费资源 Task.Run(() => { Task.Run(() => { //do something }).Wait(); Task.Run(() => { //do another thing }); });
CLR给我们提供了另一个方法:ContinueWith.
这个方法会不会堵塞当前的线程,并且会等第一个任务做好了以后再做第二个任务(当然可以开启多个)
var t = Task.Run(() => { int index = 0; int count = 0; while (index != 5) { count += index; Console.WriteLine("Task:" + index++); Thread.Sleep(1 * 1000); } return count; }); t.ContinueWith(task => { //这里的参数Task,就是我们上面那个线程对象(t),可以用于获取结果集,状态等数据 Console.WriteLine("First continue task:" + task.Status); Console.WriteLine("First continue task:" + (task.Result + 100)+"/n"); }); t.ContinueWith(task => { Console.WriteLine("Second continue task:" + task.Status); Console.WriteLine("Second continue task:" + (task.Result - 100)); }); t.ContinueWith(task => { //Do another thing });
需求肯定是很复杂的,比如我们希望在各种状态(取消,完成,失败等)情况下执行各种ContinueWith的方法,这个时候我们需要关注一个枚举类型:TaskContinuationOptions, 以下给出官方的定义:
namespace System.Threading.Tasks{ // Summary: // Specifies the behavior for a task that is created by using the System.Threading.Tasks.Task.ContinueWith(System.Action<System.Threading.Tasks.Task>,System.Threading.CancellationToken,System.Threading.Tasks.TaskContinuationOptions,System.Threading.Tasks.TaskScheduler) // or System.Threading.Tasks.Task<TResult>.ContinueWith(System.Action<System.Threading.Tasks.Task<TResult>>,System.Threading.Tasks.TaskContinuationOptions) // method. [Serializable] [Flags] public enum TaskContinuationOptions { // Summary: // Default = "Continue on any, no task options, run asynchronously" Specifies // that the default behavior should be used. Continuations, by default, will // be scheduled when the antecedent task completes, regardless of the task's // final System.Threading.Tasks.TaskStatus. None = 0, // // Summary: // A hint to a System.Threading.Tasks.TaskScheduler to schedule a task in as // fair a manner as possible, meaning that tasks scheduled sooner will be more // likely to be run sooner, and tasks scheduled later will be more likely to // be run later. PreferFairness = 1, // // Summary: // Specifies that a task will be a long-running, course-grained Operation. It // provides a hint to the System.Threading.Tasks.TaskScheduler that oversubscription // may be warranted. LongRunning = 2, // // Summary: // Specifies that a task is attached to a parent in the task hierarchy. AttachedToParent = 4, // // Summary: // Specifies that an System.InvalidOperationException will be thrown if an attempt // is made to attach a child task to the created task. DenyChildAttach = 8, // // Summary: // Prevents the ambient scheduler from being seen as the current scheduler in // the created task. This means that operations like StartNew or ContinueWith // that are performed in the created task will see System.Threading.Tasks.TaskScheduler.Default // as the current scheduler. HideScheduler = 16, // // Summary: // In the case of continuation cancellation, prevents completion of the continuation // until the antecedent has completed. LazyCancellation = 32, // // Summary: // Specifies that the continuation task should not be scheduled if its antecedent // ran to completion. This option is not valid for multi-task continuations. NotOnRanToCompletion = 65536, // // Summary: // Specifies that the continuation task should not be scheduled if its antecedent // threw an unhandled exception. This option is not valid for multi-task continuations. NotOnFaulted = 131072, // // Summary: // Specifies that the continuation task should be scheduled only if its antecedent // was canceled. This option is not valid for multi-task continuations. OnlyOnCanceled = 196608, // // Summary: // Specifies that the continuation task should not be scheduled if its antecedent // was canceled. This option is not valid for multi-task continuations. NotOnCanceled = 262144, // // Summary: // Specifies that the continuation task should be scheduled only if its antecedent // threw an unhandled exception. This option is not valid for multi-task continuations. OnlyOnFaulted = 327680, // // Summary: // Specifies that the continuation task should be scheduled only if its antecedent // ran to completion. This option is not valid for multi-task continuations. OnlyOnRanToCompletion = 393216, // // Summary: // Specifies that the continuation
新闻热点
疑难解答