簡體   English   中英

異步無效還是Task.Run?

[英]Async void or Task.Run?

考慮以下方法:

public Status SendMessage(InParam inParam)
{
    try
    {
        Task.Run(() => MethodAsync(inParam));
        return Status.Success;
    }
    catch (Exception ex)
    {
        // Log the exception
        return Status.Failed;
    }
}

MethodAsync方法:

public async Task<Status> MethodAsync(InParam inParam)
{
    try
    {
        return await processor.Process(inParam);
    }
    catch (Exception ex)
    {
        // Log exception
        return Status.Failed;
    }
}

和處理方法:

public async Task<Status> Process(InParam inParam)
{
    try
    {
         IMessage endpoint = (IMessage)Activator
            .CreateInstance(Type.GetType(_message.AgentDLLName), args);
         _messageDispatchers.Add(endpoint);

        foreach (IMessage dispatcher in _messageDispatchers)
        {
            await Task.Run(() => dispatcher.SendMessage(_message));
        }
        return await Task.Run(() => Status.Success);
    }
    catch (Exception ex)
    {
        // Log exception
        return Status.Failed;
    }

}

因此,用例是在某些處理工作流程結束時必須發送電子郵件。 此電子郵件發送部分要花費一些時間,用戶必須等待,因此原始開發人員將這段代碼放入了。

我試圖使SendMessage調用MethodAsync,並且不應該等待它返回。 我讀過在異步工作流中,整個堆棧需要異步才能正常工作。 SendMessage未標記為異步。

這是調用TaskArun的正確方法嗎,因為Task.Run返回了一個awaitable?

由於MethodAsync被標記為async因此調用Task.Run(() => MethodAsync(inParam)); 沒有多大意義。
如果要將其實現為“ 即發即忘 ”調用( 順便說一句BAD ),則可以簡單地調用MethodAsync(inParam); ,因為這還會“在其自身的任務中”(簡化)啟動MethodAsync內部await方法並返回該方法。 如果您隨后不“等待該等待”,則SendMessage的代碼將在其仍在運行時繼續執行。

但是,正如已經說過的那樣:“ 一勞永逸 ”在幾乎所有情況下都是不好的設計。 您能否再解釋一下用例,以便我們提供更好的方法?

更新:
如果真的沒有辦法使SendMessage async或擁有MethodAsync的同步副本,我建議您執行以下操作:

public Status SendMessage(InParam inParam)
{
    try
    {
        return AsyncPump.Run(() => MethodAsync(inParam));
    }
    catch (Exception ex)
    {
        // Log the exception
        return Status.Failed;
    }
}

使用AsyncPump您可以返回“真實結果”,並且沒有死鎖問題。
在您的SendMessage示例實現中, try / catchMethodAsync意義,因為該方法很可能在MethodAsync內部發生任何異常之前返回。

更新2 (在更新問題之后):
我建議“一路async ”。 這也意味着使SendMessage async (以及UI的所有方法),以便您可以await “實際結果”,但在等待時不要鎖定UI ...

更新3:
我也會改變

foreach (IMessage dispatcher in _messageDispatchers)
{
    await Task.Run(() => dispatcher.SendMessage(_message));
}

await Task.Run(() =>
    {
        foreach (IMessage dispatcher in _messageDispatchers)
            dispatcher.SendMessage(_message);
    });

這導致較少的上下文切換。 甚至:

await Task.Run(() => Parallel.ForEach(_messageDispatchers, d => d.SendMessage(_message)));

暫無
暫無

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

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