C# 异步完成时,非等待的异步方法调用会发生什么情况?

C# 异步完成时,非等待的异步方法调用会发生什么情况?,c#,multithreading,asynchronous,C#,Multithreading,Asynchronous,我有一个异步方法,我希望在其中调用SendAsync方法作为一个fire-and-forget服务。考虑下面的代码: public async Task HandleAsync(DoStuffCommand command) { /* * Performing various tasks.. */ _client.SendAsync(myObject); } public async Task SendAsync(MyObject myObject) {

我有一个异步方法,我希望在其中调用
SendAsync
方法作为一个fire-and-forget服务。考虑下面的代码:

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和traces。不会引发异常,但跟踪始终遵循方法调用的行为,即当两个调用都进行时,
TraceInformation
也是如此,并且当仅调用
call_1
时,仅第一个
TraceInformation
运行

我有一个异步方法,希望在其中调用SendAsync方法作为一个fire-and-forget服务

正如我在我的博客上所描述的,无论你想要满足什么要求。《火与遗忘》的一个主要问题是背景工作被遗忘了。总会有一些情况(希望很少)后台工作没有运行,或者被悄悄地删除。防止这种工作损失的唯一方法是实现可靠的分布式系统体系结构

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

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


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

不,绝对不是<代码>异步并不意味着“在另一个线程上运行”。如果要在另一个线程上运行,则必须显式地执行(例如,
Task.run
)。然而,在ASP.NET上,这几乎总是一个坏主意


如果要将工作损失降至最低,请使用
HostingEnvironment.QueueBackgroundWorkItem
;如果您想要防止工作的损失,那么要么拒绝fire and forget需求,要么实现适当的分布式体系结构。一个合适的分布式体系结构是一个具有独立工作进程(如Azure函数或Win32服务)的可靠消息队列(如Azure队列或MSMQ)。

查看您的代码,您正在同步调用
\u client.SendAsync
,因为您不需要等待对它的调用。可能call_1引发了一个异常,因此阻止了call_2的执行?这也是我调查的一个可能原因,因此我在
SendAsync
方法中添加了跟踪和try/catch,但据我所知,没有引发异常。请参阅更新。@Marcus:上下文是什么?这是ASP.NET吗?这是在Web API解决方案的域层(类库)中。“我的印象是SendAsync实现将在不同的线程上执行其工作”-这不是wait
async
/
await
所做的<代码>异步不会使线程变为存在。感谢您的澄清。然而,在我看来,“请求上下文”有点模糊。当ASP.NET应用程序收到请求时,运行时会实例化RequestContext,但在我看来,它实际上是什么以及它在该上下文中的作用似乎有点不清楚。在引擎盖下面的某个地方,我想我们无论如何都要开始穿线了?即使我使用
Task.Run
显式生成一个新线程,当RequestContext被释放时,它也会有相同的结果,不是吗?@Marcus:我实际上并不是指
RequestContext
类(直到现在我还不知道它存在)。“请求上下文”是模糊的,因为它从未被记录(它是一个概念,而不是一种类型)。它管理HttpContext.Current、区域性、安全性,可能还有其他一些更模糊的东西。它不是一根线;它可以在异步请求过程中在线程之间移动(尽管一次只能有一个线程)。
Task.Run
操作将在请求上下文之外运行。我知道它既是一个概念又是一个类,这就更加模糊了。假设
Task.Run
将“在请求上下文之外”运行,这是否意味着无论调用方法何时返回,它都将一直运行到完成?@Marcus:No;在ASP.NET上,在请求上下文之外运行代码是危险的,因为您的应用程序偶尔会被回收,这会杀死所有非请求工作。