網站首頁 編程語言 正文
一.延續任務
private async static void CallerWithAsync()
{
string result = await GreetingAsync("Stephanie");
Console.WriteLine(result);
}
static Task<string> GreetingAsync(string name)
{
return Task.Run<string>(() =>
{
Thread.Sleep(10000);
return name;
});
}
GreetingAsync方法返回一個Task<string>對象。該Task<string>對象包含任務創建的信息,并保存到任務完成。Task類的ContinueWith方法定義了任務完成后就調用的代碼。
private static void CallerWithContinuationTask()
{
var t1 = GreetingAsync("Stephanie");
t1.ContinueWith(t =>
{
string result = t.Result;
Console.WriteLine(result);
});
}
由于不使用await,線程不會在方法中等待,會執行完CallerWithContinuationTask()的代碼。不會再ContinueWith這里等待,所以需要一個前臺線程,不然會關閉所以線程。
二.同步上下文
CallerWithAsync和CallerWithContinuationTask方法在方法的不同階段使用了不同的線程。
static Task<string> GreetingAsync(string name)
{
return Task.Run<string>(() =>
{
Thread.Sleep(10000);
Console.WriteLine("running greetingasync in thread {0} and task {1}", Thread.CurrentThread.ManagedThreadId, Task.CurrentId);
return name;
});
}
private async static void CallerWithAsync()
{
Console.WriteLine("started CallerWithAsync in thread {0} and task {1}", Thread.CurrentThread.ManagedThreadId, Task.CurrentId);
string result = await GreetingAsync("Stephanie");
Console.WriteLine(result);
Console.WriteLine("finished GreetingAsync in thread {0} and task {1}", Thread.CurrentThread.ManagedThreadId, Task.CurrentId);
}
private static void CallerWithContinuationTask()
{
Console.WriteLine("started CallerWithContinuationTask in thread {0} and task {1}", Thread.CurrentThread.ManagedThreadId, Task.CurrentId);
var t1 = GreetingAsync("Stephanie");
t1.ContinueWith(t =>
{
string result = t.Result;
Console.WriteLine(result);
Console.WriteLine("finished CallerWithContinuationTask in thread {0} and task {1}", Thread.CurrentThread.ManagedThreadId, Task.CurrentId);
});
}
使用async和await關鍵字,當await完成后,不需要進行任何處理,就能訪問UI線程。默認情況下,生成的代碼就會把線程轉換到擁有同步上下文的線程中。調用異步方法的線程分配給了同步上下文,await完成之后將繼續執行。
如果不使用相同的同步上下文,必須調用Task類的ConfigureAwait(false).例如,一個WPF應用程序,其await后面的代碼沒有任何用到UI元素的代碼。在這種情況下,避免切換到同步上下文會執行的更快。
string s1 = await GreetingAsync("Stephanie").ConfigureAwait(false);
三.使用多個異步方法
在一個異步方法里,可以調用一個或多個異步方法。如何編寫代碼,取決于一個異步方法的結果是否取決于另一個異步方法。
1.按順序調用異步方法
下面的例子,第第二個異步方法依賴于第一個異步方法的結果,await關鍵字就很有用。
private async static void MultipleAsyncMethods()
{
string s1 = await GreetingAsync("Stephanie");
string s2 = await GreetingAsync(s1);
Console.WriteLine("Finished both methods.\n Result 1: {0}\n Result 2: {1}", s1, s2);
}
2.使用組合器
如果第二個異步方法獨立于第一個,每個異步方法可以都不使用await,而是把每個異步方法的返回結果賦值給Task變量,就會運行的更快。
private async static void MultipleAsyncMethodsWithCombinators1()
{
Task<string> t1 = GreetingAsync("Stephanie");
Task<string> t2 = GreetingAsync("Matthias");
await Task.WhenAll(t1, t2);
Console.WriteLine("Finished both methods.\n Result 1: {0}\n Result 2: {1}", t1.Result, t2.Result);
}
- Task.WhenAll組合器可以接受多個同一類型的參數,并返回同一類型的值。
- Task.WhenAll是在所有傳入方法的任務都完成了才返回Task。
- WhenAny是在其中一個傳入方法的任務完成了就返回。
Task.WhenAll定義了幾個重載版本。如果所有的任務返回相同的類型,那么該類型的數組可用于await返回的結果。
string[] result = await Task.WhenAll(t1, t2);
四.轉換異步模式
https://www.jb51.net/article/244023.htm講了三種異步編程的模式。
并非所有的.NET Framework類在.NET 4.5中都引入了新的異步方法。還有許多類只提供類BeginXXX和EndXXX方法的異步模式,可以使用TaskFactory類的FromAsync方法,它可以把使用異步模式的方法轉換為基于任務的異步模式的方法。
/創建一個委托,并引用同步方法Greeting
private static Func<string, string> greetingInvoker = Greeting;
static IAsyncResult BeginGreeting(string name, AsyncCallback callback, object state)
{
return greetingInvoker.BeginInvoke(name, callback, state);
}
static string EndGreeting(IAsyncResult ar)
{
return greetingInvoker.EndInvoke(ar);
}
//FromAsync方法的前兩個參數是委托類型,傳入BeginGreeting, EndGreeting的地址。后兩個參數是輸入的參數和對象狀態參數。
private static async void ConvertingAsyncPattern()
{
string r = await Task<string>.Factory.FromAsync<string>(BeginGreeting, EndGreeting, "Angela", null);
Console.WriteLine(r);
}
五.錯誤處理
如果調用異步方法沒有等待,將異步方法放在try/catch中,就不捕獲不到異常。
private static void DontHandle()
{
try
{
ThrowAfter(200, "first");
// exception is not caught because this method is finished before the exception is thrown
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
static async Task ThrowAfter(int ms, string message)
{
Console.Write("xxx");
await Task.Delay(ms);
throw new Exception(message);
}
DontHandle方法調用ThrowAfter后,不會在該處等待,會繼續執行,不再保持對ThrowAfter方法的引用。
注意:返回void的異步方法永遠不會等待.異步方法最好返回一個Task類型。
1.異步方法的異常處理
使用await關鍵字,將其放在在try/catch中
private static async void HandleOneError()
{
try
{
await ThrowAfter(2000, "first");
}
catch (Exception ex)
{
Console.WriteLine("handled {0}", ex.Message);
}
}
2.多個異步方法的異常處理
如果按照下面的代碼,第二個異常將不會拋出。因為第一個異常已經拋出,直接調到catch塊內了。
private static async void StartTwoTasks()
{
try
{
await ThrowAfter(2000, "first");
await ThrowAfter(1000, "second"); // the second call is not invoked because the first method throws an exception
}
catch (Exception ex)
{
Console.WriteLine("handled {0}", ex.Message);
}
}
使用Task.WhenAll,不管任務是否拋出異常,都會等到兩個任務完成。所以會拋出兩個異常。
但是,只能看見傳遞給Task.WhenAll方法的第一個任務的異常信息,雖然第二個異常會拋出,但不會顯示:
private async static void StartTwoTasksParallel()
{
Task t1 = null;
Task t2 = null;
try
{
t1 = ThrowAfter(2000, "first");
t2 = ThrowAfter(1000, "second");
await Task.WhenAll(t1, t2);
}
catch (Exception ex)
{
// just display the exception information of the first task that is awaited within WhenAll
Console.WriteLine("handled {0}", ex.Message);
}
}
3.使用AggregateException信息返回顯示異常
將Task.WhenAll返回的結果寫到一個Task變量中,catch語句只檢索到第一個任務的異常,但可以訪問外部任務taskResult的Exception屬性。Exception屬性是AggregateException類型。這個異常類型定義了InnerExceptions屬性,它包含了等待中的所有異常的列表。
private static async void ShowAggregatedException()
{
Task taskResult = null;
try
{
Task t1 = ThrowAfter(2000, "first");
Task t2 = ThrowAfter(1000, "second");
await (taskResult = Task.WhenAll(t1, t2));
}
catch (Exception ex)
{
// just display the exception information of the first task that is awaited within WhenAll
Console.WriteLine("handled {0}", ex.Message);
foreach (var ex1 in taskResult.Exception.InnerExceptions)
{
Console.WriteLine("inner exception {0} from task {1}", ex1.Message, ex1.Source);
}
}
}
六.取消異步方法
如果后臺任務可能運行很長時間,就可能用的取消任務。
取消框架基于協助行為,不是強制性的。一個運行時間很長的任務需要檢查自己是否被取消,在這種情況下,它的工作就是清理所有已打開的資源,并結束相關工作。
取消基于CancellationTokenSource類,該類可用于發送取消請求。請求發送給引用CancellationToken類的任務,其中CancellationToken類和CancellationTokenSource相關聯。
private CancellationTokenSource cts = new CancellationTokenSource();
//添加一個按鈕,用于取消正在運行的任務。使用cts.Cancel();
private void button5_Click(object sender, EventArgs e)
{
if (cts != null)
cts.Cancel();
}
private async void button4_Click(object sender, EventArgs e)
{
string s = await AsyncTaskTest();
}
//向Task類的Run方法傳遞CancellationToken參數。但需要檢查是否請求了取消操作。
Task<string> AsyncTaskTest()
{
return Task.Run(() =>
{
cts.Token.ThrowIfCancellationRequested();
Thread.Sleep(5000);
return "異步完成";
}
, cts.Token);
}
原文鏈接:https://www.cnblogs.com/afei-24/p/6758058.html
相關推薦
- 2022-10-05 Iptables防火墻基本匹配條件應用詳解_安全相關
- 2023-05-08 C語言中隊列的結構和函數接口的使用示例_C 語言
- 2022-04-16 python基礎之定義類和對象詳解_python
- 2022-11-04 React項目中使用Redux的?react-redux_React
- 2022-05-10 MAC m1使用homebrew安裝redis報錯
- 2022-09-16 c#解析jobject的數據結構_C#教程
- 2024-01-11 使用@RestController跳轉頁面
- 2023-01-15 Go語言使用組合的思想實現繼承_Golang
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支