Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/290.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 异步void的替换_C#_.net_Async Await_Task Parallel Library - Fatal编程技术网

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
方法是不好的做法,但是:

  • 我不知道他们在我的场景中会造成什么伤害
  • 如果我将
    Start
    方法更改为return
    Task
    ,它的返回值将永远不会在任何地方使用,我想不出为什么需要它

如果有人能澄清这几点,我将不胜感激。一个异步的void方法是一个“fire-and-forget”操作。您不能等待任何结果,也不知道操作何时完成以及是否成功

基本上,当您确定永远不需要知道操作何时完成以及操作执行是否成功(例如写入日志)时,应该使用void

使用返回
任务
的异步方法,调用方可以等待操作完成,还可以处理操作执行期间发生的异常


总之,如果您不需要结果,那么异步
任务
会稍微好一些,因为您可以等待它,也可以处理异常和处理任务排序

不知道是否重复,但可能是:使用
async void
唯一有意义的地方是当您需要在同步上下文上处理事件处理程序时-同步上下文使其安全,并且事件处理程序不得返回值。在其他任何地方使用
异步任务
——没有理由不这样做。您的代码看起来已经有点可疑-例如,使用
Task.Factory.StartNew
而不是
Task.Run
并使用它启动异步方法。为什么不使用task
Start
returns来跟踪长时间运行的操作的状态,而不是您自己的(可能是线程不安全的)标志呢?@Luaan,我不返回
task
,因为我不需要调用代码中的
task
对象(我正在跟踪操作状态usnig其他方式)。如果我将其更改为return
Task
并保持调用的原样,我会收到一条警告,建议将
wait
添加到调用中,这是我根本不需要的。在任何情况下,我想知道的是此代码会导致哪些特定问题有趣的是,您关心此警告,但与警告中的消息无关-该警告同样适用于您的
async void
案例。只是编译器无法知道在这种情况下该方法是否是异步的,因为
async
不是签名的一部分。您通过使用
async void
来抑制警告,就像您稍后使用
#pragma
来抑制警告一样,但更糟糕的是,因为它不太可见。它不会导致任何特定的问题-这只是一种不好的做法,它会阻止调用方跟踪异步操作。即使对于编写日志这样的操作,您也决不能对异步方法使用void return,这是它们仅用于特殊事件case@MrinalKamboj, “即使是写日志这样的操作,你们也永远不能使用void return”-为什么不呢?@Andre Borges请检查上面J Steen提供的链接,这将详细回答你们的问题。即使你们想发射并忘记,你们也不想做的是,无法控制那个次呼叫的失败,从而影响你们当前的呼叫