Task
Task
延續上一篇分享的執行緒池,執行緒池的使用還是有些許缺點,例如並不知道操作什麼時候會結束,無法有回傳值。所以 .NET Framework 提供了一個 Task的概念,Task可以知道工作什麼時候結束,而且結束的時候可以回傳一個Result。
Task用法
當Task任務結束後,可以從Result屬性取得該結果職,此時如果Task還沒結束,則執行緒會停在取Result屬性的地方,直到任務完成。
public class TaskDemo
{
public void Run()
{
Task<int> task = Task.Run<int>
(
() => Enumerable.Range(0,10000).Sum(x => x)
);
Console.WriteLine("程式執行中....");
Console.WriteLine("取得結果:{0}",task.Result); // 如果Task還沒結束,則執行緒會停在這邊
}
}
接續工作(Continuation)
任務結束後,可直自動呼叫接續作業,不必等到取Result值才做後續動作。
Task<int> task = Task.Run<int>
(
() => Enumerable.Range(0, 10000).Sum(x => x)
);
task.ContinueWith(x =>
{
// Task任務結束後,會直接跑這段程式碼
var sum = x.Result;
Console.WriteLine("接續作業取值:{0}",sum);
});
Console.WriteLine("程式執行中....");
Console.WriteLine("取得結果:{0}", task.Result); // 使用接續作業,不影響其他地方取得Result屬性
用ContinueWith的方式,當Task出錯,則Exception會在整合在AggregateException之中。
另一種接續工作方式(GetAwaiter)
Task<int> task = Task.Run<int>
(
() => Enumerable.Range(0, 10000).Sum(x => x)
);
TaskAwaiter<int> awaiter = task.GetAwaiter();
awaiter.OnCompleted(() =>
{
// Task任務結束後,會直接跑這段程式碼
var sum = awaiter.GetResult();
Console.WriteLine("接續作業取值:{0}", sum);
});
Console.WriteLine("程式執行中....");
Console.WriteLine("取得結果:{0}", task.Result); // 使用接續作業,不影響其他地方取得Result屬性
C# 5.0的非同步功能就是使用這種接續方式。 此方法會在Task完成或出錯之後執行一個委派,如果Task出現錯誤,那麼接續工作呼叫awaiter.GetResult()就是拋出例外,且此例外是直接拋出,並不會整合在AggregateException之中。
CancellationToken
如果執行緒執行時間太長,.NET Framework有提供特殊的類別,可以取消該Task的工作,稱CancellationToken。 使用CancellationToke要特別注意取消時會拋出OperationCanceledException,並且該Exception會被整合在AggregateException之中。
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
CancellationToken token = cancellationTokenSource.Token;
Task task = Task.Run(() =>
{
while (!token.IsCancellationRequested)
{
Console.WriteLine("執行中....");
Thread.Sleep(3000);
}
// 接受到取消的指令,拋出OperationCanceledException,停止Task的執行
token.ThrowIfCancellationRequested();
}, token);
try
{
Console.WriteLine("Press enter to cancel the task");
Console.ReadLine();
// 取消Task執行
cancellationTokenSource.Cancel();
// 等待任務完成
task.Wait();
}
catch (AggregateException e)
{
Console.WriteLine(e.InnerExceptions[0].Message);
Console.WriteLine("已取消完成");
}
Task是ThreadPool的進化版,幫我們封裝了很多方便的功能,又因為是從ThreadPool取得執行緒,效率上也很快。
一天一分享,身體好健康。
該追究的不是過去的原因,而是現在的目的。