考虑这种方法:
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返回一个等待的吗?
答案 0 :(得分:1)
由于MethodAsync
被标记为async
,所以通话Task.Run(() => MethodAsync(inParam));
没有多大意义。
如果您想将其实现为“ fire-and-forget ” - 请致电( BAD ),您只需致电MethodAsync(inParam);
,因为这也是在自己的任务“(简化)中启动await
内的MethodAsync
ed方法并返回该方法。如果您没有“等待那个等待”,SendMessage
中的代码将在它仍在运行时继续执行。
但正如已经说过的那样:“ fire-and-forget ”在几乎所有情况下都是糟糕的设计。你能解释一下你的用例吗,我们可以提供更好的方法吗?
更新:
如果真的没有办法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
/ 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)));