簡體   English   中英

為什么異步/等待異步運行?

[英]Why won't this async/await run asynchronously?

我一直在尋找答案,但是根據許多指南和SO問題,該代碼對我來說仍然是正確的,但它可以同步運行。

private void CheckConditions()
{
    foreach (var obj in myObjects)
    {
        if (obj.ConditionMet)
        {
            HandleConditionAsync(obj);
        }
    }
    DoOtherWork();
}

private async void HandleConditionAsync(MyObject obj)
{
    // shouldn't control transfer back to CheckConditions() here while we wait for user input?
    string userInput = await obj.MessagePromptAsync("hello user");
    DoSomeBookkeeping(obj);
}

// (MyObject.cs)
private MessagePrompt messagePrompt; // inherits from UserControl
public async Task<string> MessagePromptAsync(string prompt)
{
    return await Task.FromResult<string>(messagePrompt.Prompt(prompt));
}

// (MessagePrompt.cs)
public string Prompt(string prompt)
{
    this.UIThread(() => this.SetMessagePrompt(prompt));
    userInputAutoResetEvent.WaitOne();
    return myResult; // set in a button handler that also sets the AutoResetEvent
}

我打算讓CheckConditions()繼續愉快地運行,但是盡管我處於異步/喚醒狀態,但它仍卡在MessagePrompt的AutoResetEvent上。 我唯一能想到的是錯誤的是,由於UserControl的某些限制,其對UI線程引用的使用或堆棧頂部的非異步方法,MessagePrompt的方法可能無法異步運行。

您的代碼中沒有異步的東西。 您擁有的唯一任務是根據結果值創建的,這意味着Prompt()方法必須完成並返回其結果,然后才能返回Task對象以等待。 該對象將已經完成,因此一旦它具有要等待的Task ,所有await對象都會立即完成。

也許您的意思是這樣的:

public async Task<string> MessagePromptAsync(string prompt)
{
    return await Task.Run(() => messagePrompt.Prompt(prompt));
}

或者(如果您確實在MessagePromptAsync()方法中沒有其他東西):

public Task<string> MessagePromptAsync(string prompt)
{
    return Task.Run(() => messagePrompt.Prompt(prompt));
}

請注意,這可能會導致另一個問題,具體取決於DoOtherWork()UIThread()實際操作。 如果您的UI線程陷入DoOtherWork() ,並且UIThread()方法包裝了Dispatcher.Invoke()或類似的東西,那么您將陷入僵局。

如果那不能解決您的問題,請提供一個可靠的最小,完整和可驗證的代碼示例 ,以可靠地重現該問題。

您還需要使CheckConditions()異步,然后等待對HandleConditionAsync(MyObject obj)的調用。 CheckConditions()在您的示例中同步運行。

private async Task CheckConditionsAsync()
{
    foreach (var obj in myObjects)
    {
        if (obj.ConditionMet)
        {
            await HandleConditionAsync(obj);
        }
    }
    DoOtherWork();
}

另外,這只是最佳做法,異步方法應盡可能返回Task。 我唯一必須使用async void是為了與事件處理程序兼容。 您可以看到我以這種方式更改了CheckConditions() ,並且應該類似地修改HandleConditionAsync(MyObject obj) 我還更改了方法名稱以表示它的異步行為。

如果您需要運行一種方法來同步返回Task (並且您不應該這樣做,這表明您的設計有誤),則可以使用Task.FromResult(MyMethodAsync())來運行它。 同樣,避免在任何可能的地方執行此操作,這首先使實現與方法異步的目的無效。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM