调用异步方法时使用.Wait()的情况是什么

时间:2015-09-18 14:59:46

标签: c# asynchronous asp.net-mvc-5 async-await entity-framework-6

我的asp.net mvc-5 Web应用程序中有以下async长时间运行的方法: -

 public async Task<ScanResult> ScanAsync(string FQDN)
 {
    // sample of the operation i am doing 
    var c = await context.SingleOrDefaultAsync(a=>a.id == 1);
    var list = await context.Employees.ToListAsync();
    await context.SaveChangesAsync();
    //etc..
}

我正在使用支持运行后台作业的Hangfire工具及时调用此异步方法,但不幸的是,hangefire工具不支持直接调用异步方法。所以为了克服这个问题,我创建了上述方法的同步版本,如下所示: -

public void Scan()
{
    ScanAsync("test").Wait();
}

然后从HangFire调度程序我调用sync方法如下: -

RecurringJob.AddOrUpdate(() => ss.Scan(), Cron.Minutely);

所以我知道在方法执行期间使用.Wait()将主要占用iis线程,但正如我所提到的,我需要这样做,因为我无法在hangefire调度程序中直接调用异步TASK

那么当我使用.Wait()调用异步方法时会发生什么?,整个方法的操作是否会以同步方式完成?例如,如上所示,我在ScanAsync(); SingleOrDefualtAsyncToListAsync&amp;内部有三个异步操作。 SaveChangesAsync,所以它们会以同步的方式执行,因为我使用.wait()调用ScanAsync方法吗?

2 个答案:

答案 0 :(得分:3)

  

那么当我使用.Wait()调用异步方法时会发生什么?   整个方法的操作是否会以同步方式完成?例如   如上所示,我在ScanAsync()内部有三个异步操作   ; SingleOrDefualtAsync,ToListAsync&amp; SaveChangesAsync,他们也是   以同步方式执行,因为我正在调用ScanAsync方法   .wait()?

查询数据库的方法仍然是异步执行的,但是你调用Wait的事实意味着即使你正在发布该线程,它也不会像你那样返回到ASP.NET ThreadPool。重新制止它。

这也是一种死锁的可能性,因为ASP.NET有一个自定义同步上下文,可确保在继续执行异步调用时可以使用请求的上下文。

我建议您使用entity-framework提供的同步API,因为您实际上不会享受异步调用可以获得的可伸缩性。

修改

在评论中,你问:

  

正如我目前正在使用hangefire消除异步效应?如果是,那么使用同步方法会更好吗?或者使用hangeffire的同步或异步将完全相同

首先,您必须了解异步的好处是什么。你不这样做是因为它很酷,你这样做是因为它有用。那个目的是什么?能够在负载下扩展。它是如何做到的?当您await异步方法时,控制权将返回给调用者。例如,您有一个传入请求,您查询数据库。您可以坐在那里等待查询完成,或者您可以重新使用该线程来提供更多不一致的请求。这才是真正的力量。

如果你实际上没有计划接收大量的请求(这样你就会让线程池挨饿),你实际上看不到异步的任何好处。目前,您实施它的方式,您将看不到任何这些好处,因为您阻止了异步调用。所有你可能会看到的都是死锁。

答案 1 :(得分:0)

这在很大程度上取决于HangFire的实施方式。如果它只是在ThreadPool中调用要调用的任务,那么唯一的影响是,在请求结束之前,您的一个线程将被阻塞。但是,如果存在自定义SynchronizationContext,则可能会导致严重的死锁。

考虑一下,如果你真的想等待你的预定工作完成。也许你想要的只是一个火与忘记模式。这样你的方法就像:

public void Scan()
{
    ScanAsync("test"); // smoothly ignore the task
}

如果您确实需要等待,可以尝试使用async void方法:

public async void Scan()
{
    await ScanAsync("test");
    DoSomeOtherJob();
}

关于使用async void有很多争议,因为您不能等待此方法结束,也无法处理可能的错误。

但是,在事件驱动的应用程序中,这可能是唯一的方法。有关更多信息,请参阅:Async Void, ASP.Net, and Count of Outstanding Operations