網(wǎng)站首頁 編程語言 正文
一.延續(xù)任務(wù)
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>對象包含任務(wù)創(chuàng)建的信息,并保存到任務(wù)完成。Task類的ContinueWith方法定義了任務(wù)完成后就調(diào)用的代碼。
private static void CallerWithContinuationTask()
{
var t1 = GreetingAsync("Stephanie");
t1.ContinueWith(t =>
{
string result = t.Result;
Console.WriteLine(result);
});
}
由于不使用await,線程不會在方法中等待,會執(zhí)行完CallerWithContinuationTask()的代碼。不會再ContinueWith這里等待,所以需要一個前臺線程,不然會關(guān)閉所以線程。
二.同步上下文
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關(guān)鍵字,當(dāng)await完成后,不需要進(jìn)行任何處理,就能訪問UI線程。默認(rèn)情況下,生成的代碼就會把線程轉(zhuǎn)換到擁有同步上下文的線程中。調(diào)用異步方法的線程分配給了同步上下文,await完成之后將繼續(xù)執(zhí)行。
如果不使用相同的同步上下文,必須調(diào)用Task類的ConfigureAwait(false).例如,一個WPF應(yīng)用程序,其await后面的代碼沒有任何用到UI元素的代碼。在這種情況下,避免切換到同步上下文會執(zhí)行的更快。
string s1 = await GreetingAsync("Stephanie").ConfigureAwait(false);
三.使用多個異步方法
在一個異步方法里,可以調(diào)用一個或多個異步方法。如何編寫代碼,取決于一個異步方法的結(jié)果是否取決于另一個異步方法。
1.按順序調(diào)用異步方法
下面的例子,第第二個異步方法依賴于第一個異步方法的結(jié)果,await關(guān)鍵字就很有用。
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.使用組合器
如果第二個異步方法獨(dú)立于第一個,每個異步方法可以都不使用await,而是把每個異步方法的返回結(jié)果賦值給Task變量,就會運(yùn)行的更快。
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組合器可以接受多個同一類型的參數(shù),并返回同一類型的值。
- Task.WhenAll是在所有傳入方法的任務(wù)都完成了才返回Task。
- WhenAny是在其中一個傳入方法的任務(wù)完成了就返回。
Task.WhenAll定義了幾個重載版本。如果所有的任務(wù)返回相同的類型,那么該類型的數(shù)組可用于await返回的結(jié)果。
string[] result = await Task.WhenAll(t1, t2);
四.轉(zhuǎn)換異步模式
https://www.jb51.net/article/244023.htm講了三種異步編程的模式。
并非所有的.NET Framework類在.NET 4.5中都引入了新的異步方法。還有許多類只提供類BeginXXX和EndXXX方法的異步模式,可以使用TaskFactory類的FromAsync方法,它可以把使用異步模式的方法轉(zhuǎn)換為基于任務(wù)的異步模式的方法。
/創(chuàng)建一個委托,并引用同步方法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方法的前兩個參數(shù)是委托類型,傳入BeginGreeting, EndGreeting的地址。后兩個參數(shù)是輸入的參數(shù)和對象狀態(tài)參數(shù)。
private static async void ConvertingAsyncPattern()
{
string r = await Task<string>.Factory.FromAsync<string>(BeginGreeting, EndGreeting, "Angela", null);
Console.WriteLine(r);
}
五.錯誤處理
如果調(diào)用異步方法沒有等待,將異步方法放在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方法調(diào)用ThrowAfter后,不會在該處等待,會繼續(xù)執(zhí)行,不再保持對ThrowAfter方法的引用。
注意:返回void的異步方法永遠(yuǎn)不會等待.異步方法最好返回一個Task類型。
1.異步方法的異常處理
使用await關(guān)鍵字,將其放在在try/catch中
private static async void HandleOneError()
{
try
{
await ThrowAfter(2000, "first");
}
catch (Exception ex)
{
Console.WriteLine("handled {0}", ex.Message);
}
}
2.多個異步方法的異常處理
如果按照下面的代碼,第二個異常將不會拋出。因?yàn)榈谝粋€異常已經(jīng)拋出,直接調(diào)到catch塊內(nèi)了。
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,不管任務(wù)是否拋出異常,都會等到兩個任務(wù)完成。所以會拋出兩個異常。
但是,只能看見傳遞給Task.WhenAll方法的第一個任務(wù)的異常信息,雖然第二個異常會拋出,但不會顯示:
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返回的結(jié)果寫到一個Task變量中,catch語句只檢索到第一個任務(wù)的異常,但可以訪問外部任務(wù)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);
}
}
}
六.取消異步方法
如果后臺任務(wù)可能運(yùn)行很長時間,就可能用的取消任務(wù)。
取消框架基于協(xié)助行為,不是強(qiáng)制性的。一個運(yùn)行時間很長的任務(wù)需要檢查自己是否被取消,在這種情況下,它的工作就是清理所有已打開的資源,并結(jié)束相關(guān)工作。
取消基于CancellationTokenSource類,該類可用于發(fā)送取消請求。請求發(fā)送給引用CancellationToken類的任務(wù),其中CancellationToken類和CancellationTokenSource相關(guān)聯(lián)。
private CancellationTokenSource cts = new CancellationTokenSource();
//添加一個按鈕,用于取消正在運(yùn)行的任務(wù)。使用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參數(shù)。但需要檢查是否請求了取消操作。
Task<string> AsyncTaskTest()
{
return Task.Run(() =>
{
cts.Token.ThrowIfCancellationRequested();
Thread.Sleep(5000);
return "異步完成";
}
, cts.Token);
}
原文鏈接:https://www.cnblogs.com/afei-24/p/6758058.html
相關(guān)推薦
- 2022-06-26 asp.net使用WebAPI和EF框架結(jié)合實(shí)現(xiàn)數(shù)據(jù)的基本操作_實(shí)用技巧
- 2023-06-17 tensorflow1.x和tensorflow2.x中的tensor轉(zhuǎn)換為字符串的實(shí)現(xiàn)_pytho
- 2022-09-29 React事件監(jiān)聽和State狀態(tài)修改方式_React
- 2022-06-04 解決Go語言time包數(shù)字與時間相乘的問題_Golang
- 2022-08-18 go-spew調(diào)試?yán)髟斀鈅Golang
- 2022-04-15 ASP.NET?Core托管模型CreateDefaultBuilder()方法_基礎(chǔ)應(yīng)用
- 2022-07-18 SpringMVC文件上傳功能實(shí)現(xiàn)
- 2022-12-21 使用RedisAtomicInteger計數(shù)出現(xiàn)少計問題及解決_Redis
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支