>>回傳《C# 并發編程》
- 1. 取消請求
- 2. 超時后取消
- 3. 取消并行
- 4. 取消回應式代碼
- 5. 與其他取消體系的互操作
CancellationToken.None 是一個等同于默認的特殊值,表示這個方法是永遠不會被取消的,
實體代碼
static async Task CancelableMethodAsync(CancellationToken token)
{
await Task.Delay(1000, token);
throw new ArgumentException();
}
public static async Task IssueCancelRequestAsync()
{
var cts = new CancellationTokenSource();
var task = CancelableMethodAsync(cts.Token);
// 這里,操作在正常運行,
// 發出取消請求,
cts.Cancel();
//(異步地)等待操作結束,
try
{
await task;
// 如運行到這里,說明在取消請求生效前,操作正常完成 ,
}
catch (OperationCanceledException ex)
{
// 如運行到這里,說明操作在完成前被取消,
System.Console.WriteLine(ex.GetType().Name);
}
catch (Exception ex)
{
// 如運行到這里,說明在取消請求生效前,操作出錯并結束,
System.Console.WriteLine(ex.GetType().Name);
}
}
輸出:
TaskCanceledException
1. 取消請求
public static int CancelableMethod(CancellationToken cancellationToken)
{
for (int i = 0; i != 100000; ++i)
{
// cancellationToken.WaitHandle.WaitOne(1000);
Thread.Sleep(1);
// 這里做一些計算作業,
if (i % 1000 == 0)
cancellationToken.ThrowIfCancellationRequested();
}
return 42;
}
2. 超時后取消
public static async Task IssueTimeoutAsync()
{
Stopwatch sw = Stopwatch.StartNew();
try
{
var cts = new CancellationTokenSource();
var token = cts.Token;
cts.CancelAfter(TimeSpan.FromSeconds(2));
await Task.Delay(TimeSpan.FromSeconds(4), token);
}
finally
{
System.Console.WriteLine($"{sw.ElapsedMilliseconds}ms");
}
}
輸出:
2004ms
Unhandled Exception: ... ...
只要執行代碼時用到了超時,就該使用 CancellationTokenSource 和 CancelAfter (或者用建構式),雖然還有其他途徑可實作這個功能,但是使用現有的取消體系是最簡單也是最高效的,
3. 取消并行
public class Matrix
{
public void Rotate(float degrees) { }
}
//只做展示
public static void RotateMatrices(IEnumerable<Matrix> matrices, float degrees, CancellationToken token)
{
Parallel.ForEach(matrices, new ParallelOptions
{
CancellationToken = token
},
matrix => matrix.Rotate(degrees));
}
4. 取消回應式代碼
注入取消請求
- 某一個層次的代碼需要回應取消請求,同時它本身也要向下一層代碼發出取消請求(但不會向上傳遞),
public static async Task RunGetWithTimeoutAsync()
{
CancellationTokenSource source = new CancellationTokenSource();
await GetWithTimeoutAsync("http://www.baidu.com", source.Token);
}
public static async Task<HttpResponseMessage> GetWithTimeoutAsync(string url, CancellationToken cancellationToken)
{
var client = new HttpClient();
using (var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken))
{
cts.CancelAfter(TimeSpan.FromMilliseconds(100));
var combinedToken = cts.Token;
return await client.GetAsync(url, combinedToken);
}
}
輸出:
Unhandled Exception: Unhandled exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.AggregateException: One or more errors occurred. (A task was canceled.) ---> System.Threading.Tasks.TaskCanceledException ... ...
5. 與其他取消體系的互操作
有一些外部的或以前遺留下來的代碼采用了非標準的取消模式,現在要用標準的CancellationToken 來控制這些代碼
public static async Task RunPingAsync()
{
var cts = new CancellationTokenSource();
var task = PingAsync("192.168.0.101", cts.Token);
//cts.Cancel();
await task;
}
public static async Task<PingReply> PingAsync(string hostNameOrAddress, CancellationToken cancellationToken)
{
Stopwatch sw = Stopwatch.StartNew();
try
{
var ping = new Ping();
using (cancellationToken.Register(() => ping.SendAsyncCancel()))
{
return await ping.SendPingAsync(hostNameOrAddress);
}
}
finally
{
System.Console.WriteLine($"{sw.ElapsedMilliseconds}ms");
}
}
注意: 為了避免記憶體和資源的泄漏,一旦不再需要使用回呼函式了,就要釋放這個回呼函式注冊,
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/75335.html
標籤:C#
上一篇:執行緒安全集合
下一篇:執行緒同步
