一个非等待的异步方法调用异步完成会发生什么?

时间:2016-05-23 13:59:59

标签: c# multithreading asynchronous

我有一个异步方法,我希望将SendAsync方法作为即发即弃服务来调用。请考虑以下代码:

public async Task HandleAsync(DoStuffCommand command)
{
    /*
    * Performing various tasks..
    */

    _client.SendAsync(myObject);
}

public async Task SendAsync(MyObject myObject)
{
    /*
    * Time consuming tasks..
    */  
    try
    {
        await call_1();
        Trace.TraceInformation("Call1");

        await call_2();
        Trace.TraceInformation("Call2");
    }
    catch (Exception e)
    {
        Trace.TraceError(e.Message);
        throw;
    }   
}

我的问题是,由于某些原因,call_2被不一致地调用(很少)。我怀疑是不允许SendAsync方法完成,因为调用方法HandleAsync没有等待SendAsync,当HandleAsync线程终止时,SendAsync正在进行的工作也是。

但是,这与我对async / await的理解相反。我的印象是SendAsync实现将在此场景中的不同线程上执行其工作,因此,即使HandleAsync将在SendAsync之前返回,也能够完成。

也许有人比我自己更多的异步/等待可以解决一些问题?谢谢。

更新

我还尝试添加try / catch和trace。没有抛出异常,但跟踪始终遵循方法调用的行为,即,当两个调用都进行时,TraceInformation和只调用call_1时,只有第一个TraceInformation运行。

1 个答案:

答案 0 :(得分:3)

  

我有一个异步方法,我希望将SendAsync方法作为即发即弃服务调用。

正如我在我的博客中描述的那样fire-and-forget on ASP.NET is inherently dangerous and almost always the wrong solution,无论你想要满足什么要求。 “火与遗忘”的主要问题之一是背景工作被遗忘。总会有一些情况(希望很少见),后台工作没有运行,或者被静默删除。防止这种工作丢失的唯一方法是实现可靠的分布式系统架构。

  

我怀疑SendAsync方法是不允许完成的,因为调用方法HandleAsync不等待SendAsync,当HandleAsync线程终止时,SendAsync中正在进行的工作也是如此。

ASP.NET不是关于线程而是关于请求上下文HandleAsync完成后,该请求的请求上下文将被释放,这可能会导致SendAsync中的某些代码失败或行为不正常。

  

我认为SendAsync实现会在这种情况下在不同的线程上执行其工作,因此,即使HandleAsync在SendAsync之前返回,也能够完成。

不,绝对没有。 async并不意味着“在另一个线程上运行”。如果要在另一个线程上运行,则必须明确地执行此操作(例如,Task.Run)。但是,这在ASP.NET上几乎总是一个坏主意。

如果您想最小化失去工作,请使用HostingEnvironment.QueueBackgroundWorkItem;如果您想阻止失去工作,那么拒绝即发即弃要求实施适当的分布式架构。适当的分布式体系结构是具有可靠消息队列(例如Azure队列或MSMQ)和独立工作进程(例如Azure Functions或Win32 Services)的体系结构。