![](/img/trans.png)
[英]Task.Run( () MethodName()) and await Task.Run(async () => MethodName())
[英]Specific exceptions are not shown when using async/await and Task.Run
我有一個包含食譜列表的網頁。 在我的代碼中,我遍歷頁面並下載每個配方。 這是我正在做的偽代碼:
//This is the Recipe class
//The constructor accepts a link to the recipe
//This method scrapes the recipe
public Task ScrapeAsync(){
return Task.Run(async () => {
string WebPage;
WebRequest request = WebRequest.Create(link);
request.Method = "GET";
using (WebResponse response = await request.GetResponseAsync())
using (StreamReader reader = new StreamReader(response.GetResponseStream())) {
WebPage = await reader.ReadToEndAsync();
}
//Non - async code here which is used to scrape the webpage
}
}
我使用了Task.Run,因為Method中有異步和阻塞代碼。
//This is the RecipePage class
//This method scrapes the page
public Task GetRecipeListAsync(){
return Task.Run(async () => {
//I get the page using WebRequest and WebResponse in the same way as above
//Non - async/blocking code here which scrapes the page and finds links to recipes. I do await Recipe.ScrapeAsync() somewhere here.
//And I add the recipe objects to a public list in this class
}
}
在表單中,它循環遍歷頁面列表,並await RecipePage.GetRecipeList()
和其他東西。
這是for循環的位置:
private async void go_Click(object sender, EventArgs e){
for (int i = (int)startingPageNUD.Value; i <= (int)finishingPageNUD.Value; ++i) {
RecipePage page = new RecipePage(page + i);
await page.GetRecipeListAsync();
//Some other code here
}
}
我的問題是,只要ScrapeAsync
方法中發生異常,Visual Studio 2013就會指向Application.Run(new Form1())
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
並告訴我Reflection.TargetInvocationException
已經發生。 它沒有在我的代碼中顯示實際的異常。 例如,如果我在代碼中得到NullReferenceException
,則不會顯示。 因此,我必須編寫異步和非異步代碼,並使用非異步代碼進行調試。 有什么方法可以解決這個問題嗎?
我也有另一個問題。 我是否以正確的方式使用async / await和Task?
我是否以正確的方式使用async / await和Task?
很接近了。 我認為在這種情況下不需要Task.Run
(它應該僅用於從UI線程中Task.Run
CPU密集型操作,並且HTML抓取通常足夠快以保持在UI上而沒有任何不利影響)。
我提出的另一個建議是讓async Task
方法盡可能多地返回值,而不是將成員變量修改為副作用。 在您的情況下,考慮讓ScrapeAsync
返回自己的列表而不是更新共享列表,並讓調用代碼執行列表合並。
關於您的異常, TargetInvocationException
將具有包含詳細信息的InnerException
。 async void
事件處理程序中的異常管理實際上與常規void
事件處理程序中的異常相同:如果一個轉義事件處理程序,則轉到應用程序主循環。 如果你不想這樣,你就必須抓住它(對於同步和異步處理程序)。
將getRecipeList代碼封裝在try / catch中。
在catch代碼中,獲取異常消息和堆棧跟蹤並將它們分配給Recipe類的變量,當操作完成時,您將在主線程中測試/顯示它們。
private string TheException = "" ;
public Task GetRecipeListAsync()
{
TheException = "" ;
Task result = Task.Run(async () =>
{
try
{
//I get the page using WebRequest and WebResponse in the same way as above
...
}
catch (Exception Ex)
}
if (TheException!="") MessageBox.show(TheException) ;
// or Throw an exception with
return result ;
}
您也可以在GoClick過程中測試“TheExceptio”。
好的。 感謝您的編輯,我現在可以回答。
你的問題是這個功能:
private async void go_Click(object sender, EventArgs e){
for (int i = (int)startingPageNUD.Value; i <= (int)finishingPageNUD.Value; ++i) {
RecipePage page = new RecipePage(page + i);
await page.GetRecipeListAsync();
//Some other code here
}
}
問題是該函數一旦到達await
就會返回到它所調用的內容。 現在如果page.GetRecipeListAsync();
拋出異常,這個異常會在continuation handler中拋出。 此處理程序在UI的任務隊列中執行。 拋出異常會導致UI的任務循環崩潰,這會產生各種有趣的影響,包括奇怪的異常。
在async void
函數中,您應該始終通過將所有代碼包裝到try
... catch
來處理任何傳入的異常。 如果您發現異常,則崩潰應用程序是否由您決定。
事情的工作一般的做法是拋出內部的任何異常Task
,並通過在擴展async
功能被再次拋出await
。 但async void
函數不會await
任何地方await
,所以這不起作用。
關於async
的用法。 我不認為你需要將每個函數包裝到一個Task
但你可以這樣做。 通常你不需要像這樣強迫它進入背景。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.