Async void或Task.Run?

时间:2014-10-13 11:28:39

标签: c# async-await

考虑这种方法:

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;
    }
}

和Process方法:

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未标记为异步。

这是调用MethodAsync的正确方法,因为Task.Run返回一个等待的吗?

1 个答案:

答案 0 :(得分:1)

由于MethodAsync被标记为async,所以通话Task.Run(() => MethodAsync(inParam));没有多大意义。
如果您想将其实现为“ fire-and-forget ” - 请致电( BAD ),您只需致电MethodAsync(inParam);,因为这也是在自己的任务“(简化)中启动await内的MethodAsync ed方法并返回该方法。如果您没有“等待那个等待”,SendMessage中的代码将在它仍在运行时继续执行。

但正如已经说过的那样:“ fire-and-forget ”在几乎所有情况下都是糟糕的设计。你能解释一下你的用例吗,我们可以提供更好的方法吗?

更新:
如果真的没有办法SendMessage asyncMethodAsync同步,我推荐以下内容:

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

使用AsyncPump,您可以返回“真实结果”并且没有死锁问题 在SendMessage的示例实现中,try / catch也没那么明显,因为在MethodAsync内任何异常发生之前,该方法很可能会返回。

更新2 (更新后的问题):
我建议“一路走async”。含义也会使SendMessage async(以及所有方法直到UI),因此您可以await“真实结果”,但在等待时不要锁定UI ... < / p>

更新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)));