使用异步方法是否必须使用“await”关键字?

时间:2017-03-14 07:09:13

标签: c# asp.net .net asynchronous async-await

我有以下方法:

async Task A()
{
    HttpClient client = new HttpClient();
    string response = await client.GetStringAsync("http://msdn.microsoft.com");        
}

async Task B()
{
    HttpClient client = new HttpClient();
    string response = await client.GetStringAsync("http://google.com");
}

即调用remote api,处理响应,并且不返回任何内容。

我将通过一种常用方法将其称为:

protected void Page_Load(object sender, EventArgs e)
{
    A();
    B();

    // Do further task after this which is not dependent on response of A or B
}

编译器在A和B方法上给出了以下警告:

  

因为没有等待此调用,所以执行当前方法   在通话结束前继续。考虑应用'await'   运算符到调用的结果。

enter image description here

我不需要A或B方法的任何响应,所以我想在A()和B()前面省略“await”关键字,因为我想在A和B调用之后执行代码写了评论“//在此之后做了进一步的任务,不依赖于A或B的响应”而不等待A或B回应。

我可以忽略编译器警告吗?

我是否滥用了API?

我无法通过A和B方法删除异步运算符,因为HttpClient.GetStringAsync需要它。

修改

我去了这个链接 https://softwareengineering.stackexchange.com/questions/331353/does-omitting-await-keyword-once-in-the-call-stack-break-the-asynchronous-behavi

并找到以下评论:

“当你不等待异步方法时,它等同于调用Task.Run(()=> A())。”

这是真的吗?

4 个答案:

答案 0 :(得分:0)

基本上await确保Task完成它的执行。不使用async运行await方法就像启动Task而不监控其进度和结果一样。

例如,在ASP.Net环境中,如果任务从请求线程等启动,则可能导致任务中止。

答案 1 :(得分:0)

更新:Fire and Forget in ASP.NET

在您的代码中,在完成方法AB之前执行在此之后执行不依赖于A或B 部分响应的进一步任务(除非这些都非常快。)

当你使用await并且该方法命中该行时,它会向调用者返回Task,并且调用者继续执行第二行(在你的情况下为B),因为B执行相同操作,然后调用这两个方法后的部分执行。

<强>侧面注意:

使用await关键字的每种方法都应标记为异步,这是为了向后兼容。但是,编译器只是警告您,您不在等待调用者的结果,对于初学者来说,这在很多情况下都是一个很好的警告。

答案 2 :(得分:0)

如果你想要的是火灾和遗忘,你可以安全地忽略大多数情况下的警告(ASP.NET除外)。一些库,如Microsoft.VisualStudio.Threading,甚至提供帮助来抑制这些警告:https://msdn.microsoft.com/en-us/library/microsoft.visualstudio.threading.tplextensions.forget.aspx

你可以这样使用它:

// Forget doesn't actually do anything internally. 
// It's an empty extension method you use to prove that you actually want the task to be
// fire and forget
A().Forget();
B().Forget();

如果您在同步上下文中执行,并且该方法在内部执行await而没有ConfigureAwait(false),则您也可能会遇到一些奇怪的行为。这是.ConfigureAwait(false)应始终在库代码中使用的原因之一。

对于问题的第二部分:

  

“当你不等待异步方法时,它等同于调用Task.Run(()=&gt; A())。”

     

这是真的吗?

这是错误的。至少存在两个主要差异:

  1. 使用async方法时,第一个await之前的部分将在调用者线程中同步执行。例如:

    public async Task DoSomething()
    {
        Thread.Sleep(1000); // Will execute in the caller thread
        await SomeExternalResource();
        Thread.Sleep(1000); // Will execute in the continuation
    }
    

    这里,如果你直接调用该方法,调用者线程将在至少1秒内被阻塞(至少,因为有可能延续将在同一个线程中执行)。如果使用Task.Run,整个方法将在线程池上执行,并且不会阻塞调用者线程。

  2. 使用Task.Run执行方法而不流动当前同步上下文,这可能会在某些情况下显着改变行为

答案 3 :(得分:0)

如果A和B的执行与Page_Load流的其余部分异步,则不必await

此处给出的另一个选项是显示您明确忽略此警告给其他读取您代码的人,是用#pragma disable

包装它
#pragma warning disable warning-list  

A();
B();

#pragma warning restore warning-list