選單
GSS 技術部落格
在這個園地裡我們將從技術、專案管理、客戶對談面和大家分享我們多年的經驗,希望大家不管是喜歡或是有意見,都可以回饋給我們,讓我們有機會和大家對話並一起成長!
若有任何問題請來信:gss_crm@gss.com.tw
4 分鐘閱讀時間 (784 個字)

[.NET]From Sync to Async

unsplash-tech007

本文章記錄「No More Deadlocks – Filip Ekberg」的筆記,
從 block ui ... 使用 Task 到 async ... await ,希望對大家有所幫助。

環境:Windows Form, .NET 4.5

1.一開始在 UI 上放一個 Button(btnBlockTest) 及一個 Label (lblResult),

在 Button 的 Click 事件中,寫入以下的Code,
private void btnBlockTest_Click(object sender, EventArgs e)
{
//1.block UI Thread.Sleep(2000);
lblResult.Text = "Hello World";
}
這樣會Block UI..

 
2.因為執行比較久,所以我們將要執行的事放入Task之中,如下,
private void btnBlockTest_Click(object sender, EventArgs e)
{
var task = Task.Run(
() =>
{
Thread.Sleep(2000);
return "Hello World!";
}
);
//這裡等待Task執行結束 lblResult.Text = task.Result;
}
但還是會 Block UI..

 
3.為了不 Block UI,所以使用 Task.ContinueWith ,如下,
private void btnBlockTest_Click(object sender, EventArgs e)
{
var task = Task.Run(
() =>
{
Thread.Sleep(2000);
return "Hello World!";
}
);

task.ContinueWith(
(completedTask) =>
{
lblResult.Text = completedTask.Result;
}
);
}
雖然不會Block UI了,但 lblResult.Text 卻不會接收到 Task 的回傳值,因為它不在 UI Thread 中執行。

 
4.如果 Task 中有錯誤呢?
private void btnBlockTest_Click(object sender, EventArgs e)
{
var task = Task.Run(
() =>
{
Thread.Sleep(2000);
throw new Exception("Task Error");
return "Hello World!";
}
);

task.ContinueWith(
(completedTask) =>
{
lblResult.Text = completedTask.Result;
}
);
}
Exception 會被吃掉,因為不在 UI Thread 中執行 ...

 
5.所以我們可以判斷 Task.IsFaulted 就可以將 Exception Log 下來,如下,
private void btnBlockTest_Click(object sender, EventArgs e)
{
var task = Task.Run(
() =>
{
Thread.Sleep(2000);
throw new Exception("Task Error");
return "Hello World!";
}
);

task.ContinueWith(
(completedTask) =>
{
if (completedTask.IsFaulted)
{
Console.WriteLine(completedTask.Exception.ToString());
}else {
lblResult.Text = completedTask.Result;
}
}
);
}

處理了 Exception,再來就要處理 lblResult.Text 卻不接收到 Task 的回傳值的問題...

 
6.因為 Task.ContinueWith 並非在 UI Thread 中執行,所以設定 lblResult.Text 需要在 UI Thread 中執行,如下,
private void btnBlockTest_Click(object sender, EventArgs e)
{
var task = Task.Run(
() =>
{
Thread.Sleep(2000);
return "Hello World!";
}
);
//way1:if the current execution context is on the UI thread. //task.ContinueWith( // (completedTask) => // { // lblResult.Text = completedTask.Result; // } // , TaskScheduler.FromCurrentSynchronizationContext());
//way2 task.ContinueWith(
(completedTask) =>
{
this.Invoke((MethodInvoker)delegate {
lblResult.Text = completedTask.Result;
});
}
);
}
嗯...這樣 lblResult.Text 值就有改變了....

 
7.接下來我們使用 async ... await,如下,
private async void btnBlockTest_Click(object sender, EventArgs e)
{
var task = Task.Run(
() =>
{
Thread.Sleep(2000);
return "Hello World!";
}
);
lblResult.Text = await task;
}
功能一樣,但程式碼簡潔了許多呢 ...

 
8.相同的,如果 Task 中發生了錯誤呢?
private async void btnBlockTest_Click(object sender, EventArgs e)
{
var task = Task.Run(
() =>
{
Thread.Sleep(2000);
throw new Exception("Task Error");
return "Hello World!";
}
);

lblResult.Text = await task;
}
爆了....

 
9.將 Task 抽到 RunAsync Method,然後用 try ... catch 去包,如下,
private async void btnBlockTest_Click(object sender, EventArgs e)
{
try {
RunAsync();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}

private async void RunAsync()
{
var task = Task.Run(
() =>
{
Thread.Sleep(2000);
throw new Exception("Task Error");
return "Hello World!";
}
);

lblResult.Text = await task;
}
還是會發生錯誤 .... 因為 RunAsync 回傳值是 void 而不是 Task。

 
10.那我們將它改成 Task 呢?
private async Task RunAsync()
{
var task = Task.Run(
() =>
{
Thread.Sleep(2000);
throw new Exception("Task Error");
return "Hello World!";
}
);

lblResult.Text = await task;
}
雖然不會整個 Ap 都掛掉,但也沒有被 catch 攔到... 因為呼叫時,沒有加上 await ...

 
11.Task的Method要回傳Task,而呼叫則要加上 await,如下,
private async void btnBlockTest_Click(object sender, EventArgs e)
{
try {
await RunAsync();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
 
另外使用 Task 上也要小心 相同 Thread Blocking 狀況哦...

因為這樣就會發生 Deadlock ..... 例如 No More Deadlocks – Filip Ekberg 的範例,
Task.Delay(1).ContinueWith((t) => {
}, TaskScheduler.FromCurrentSynchronizationContext()
).Wait();
本文也發表於亂馬客Blog
[SQL]執行 xp_cmdshell 可能遇到的問題
是神話還是屁話~~工程師眼裡的專案管理

相關文章

 

評論

尚無評論
已經注冊了? 這裡登入
Guest
2024/05/05, 週日

Captcha 圖像