C# 异步void的替换
我正在开发一个用于监控某些任务的应用程序(例如,如果某些服务/网站当前正在运行,数据库中存在某些记录,等等)。由于大多数这些任务都是长时间运行的,我将C# 异步void的替换,c#,.net,async-await,task-parallel-library,C#,.net,Async Await,Task Parallel Library,我正在开发一个用于监控某些任务的应用程序(例如,如果某些服务/网站当前正在运行,数据库中存在某些记录,等等)。由于大多数这些任务都是长时间运行的,我将TPL与async/await结合使用 我有一个用于所有此类任务的基类: public abstract class LongRunningOperation { // .. some props... internal async void Start() { try {
TPL
与async/await
结合使用
我有一个用于所有此类任务的基类:
public abstract class LongRunningOperation
{
// .. some props...
internal async void Start()
{
try
{
this.Status = OperationStatus.Started;
await this.DoStart();
this.Status = OperationStatus.Finished;
}
catch (Exception e)
{
this.Status = OperationStatus.Error;
this.Message = e.ToString();
}
}
protected abstract Task DoStart();
}
启动这些任务的方法如下所示:
public static LongRunningOperation[] LaunchOperations()
{
LongRunningOperation[] operations = GetAllLongRunningOperations();
foreach (var o in operations)
Task.Factory.StartNew(() => { o.Start(); });
return operations;
}
此方法返回的数组用于监视所有LongRunningOperation
s并记录统计数据。目前,我有一个控制台应用程序,它有一个while(true)
循环,在屏幕上打印每个操作的统计信息(名称、状态、当前运行时)(每秒刷新一次),直到所有操作完成
困扰我的是异步void
方法。我已经读到使用async void
方法是不好的做法,但是:
- 我不知道他们在我的场景中会造成什么伤害
- 如果我将
方法更改为returnStart
,它的返回值将永远不会在任何地方使用,我想不出为什么需要它Task
如果有人能澄清这几点,我将不胜感激。一个异步的void方法是一个“fire-and-forget”操作。您不能等待任何结果,也不知道操作何时完成以及是否成功 基本上,当您确定永远不需要知道操作何时完成以及操作执行是否成功(例如写入日志)时,应该使用void 使用返回
任务
的异步方法,调用方可以等待操作完成,还可以处理操作执行期间发生的异常
总之,如果您不需要结果,那么异步
任务
会稍微好一些,因为您可以等待它,也可以处理异常和处理任务排序 不知道是否重复,但可能是:使用async void
唯一有意义的地方是当您需要在同步上下文上处理事件处理程序时-同步上下文使其安全,并且事件处理程序不得返回值。在其他任何地方使用异步任务
——没有理由不这样做。您的代码看起来已经有点可疑-例如,使用Task.Factory.StartNew
而不是Task.Run
并使用它启动异步方法。为什么不使用taskStart
returns来跟踪长时间运行的操作的状态,而不是您自己的(可能是线程不安全的)标志呢?@Luaan,我不返回task
,因为我不需要调用代码中的task
对象(我正在跟踪操作状态usnig其他方式)。如果我将其更改为returnTask
并保持调用的原样,我会收到一条警告,建议将wait
添加到调用中,这是我根本不需要的。在任何情况下,我想知道的是此代码会导致哪些特定问题有趣的是,您关心此警告,但与警告中的消息无关-该警告同样适用于您的async void
案例。只是编译器无法知道在这种情况下该方法是否是异步的,因为async
不是签名的一部分。您通过使用async void
来抑制警告,就像您稍后使用#pragma
来抑制警告一样,但更糟糕的是,因为它不太可见。它不会导致任何特定的问题-这只是一种不好的做法,它会阻止调用方跟踪异步操作。即使对于编写日志这样的操作,您也决不能对异步方法使用void return,这是它们仅用于特殊事件case@MrinalKamboj, “即使是写日志这样的操作,你们也永远不能使用void return”-为什么不呢?@Andre Borges请检查上面J Steen提供的链接,这将详细回答你们的问题。即使你们想发射并忘记,你们也不想做的是,无法控制那个次呼叫的失败,从而影响你们当前的呼叫