为什么异步方法总是阻塞线程?

问题描述 投票:0回答:4

我有一个像这样的异步方法:

public static async Task<bool> SendMailAsync()
{
    // ...something
}

这个方法返回结果的时间很长。

我还有其他类似的方法:

public async Task<string> ThisIsController()
{
    Task<bool> result = SendMailAsync();
    OtherMethod1();
    OtherMethod2();
    // ....
}

我没有在结果中使用await。但是

ThisIsController
总是等待结果返回然后运行
OtherMethod1()
OtherMethod2
? 谢谢你

更新1:

SendMailAsync()
的完整代码:

public static async Task<bool> SendMailAsync(List<string> listEmail, string subject, string body)
{
    try
    {
        var emailsPerMin = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings["EmailsPerMin"]
            .ToString());
        for (int i = 1; i <= System.Math.Ceiling(listEmail.Count * 1.0 / emailsPerMin); i++)
        {

            List<string> sendingList = listEmail.Skip((i - 1) * emailsPerMin).Take(emailsPerMin).ToList();
            foreach (var email in sendingList)
            {
                MailHelper.SendMail(email, subject, body);
                Thread.Sleep(60 * 1000);
            }
        }
        return true;
    }
    catch
    {
        return false;
    }
}
c# asp.net asynchronous async-await
4个回答
5
投票

添加

async
方法不会(本身)使代码异步。异步代码是 hard -
async
修饰符所做的就是启用
await
关键字(并启用一些有关返回类型的编译器魔法)。如果该方法实际上没有执行任何异步操作,那么它就不是异步的。特别是:

  • 如果一个方法没有
    await
    :从
    async
    的意义上来说,它并不是真正的异步
    • (这里有一个小警告:如果一个方法不是标记为
      async
      ,并且只是
      return
      是来自
      另一个
      方法的Task[<T>],那么它可能会暴露异步行为)
  • 如果一个方法确实
    await
    ,但所有正在等待的事情实际上总是同步完成的:它并不是真正的异步

在本例中,这是第一颗子弹。代码中没有

await
。事实上,编译器应该已经向您发出警告:

Warning  CS1998  This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

即使一个方法返回

Task[<T>]
(或其他可等待模式):如果它不是 实际上 异步(因为上面的任一项目符号):它将在返回到调用者之前运行到完成;当它这样做时,它就会被认为已经完成。

要使此代码异步,
它所做的事情

(大概是发送)需要异步。也许: foreach (var email in sendingList) { await MailHelper.SendMailAsync(email, subject, body); await Task.Delay(60 * 1000); }

注意;如果您的 
MailHelper

没有

async
API,您
也可以
只需将 delay 设为异步即可使其异步: foreach (var email in sendingList) { MailHelper.SendMail(email, subject, body); await Task.Delay(60 * 1000); }

最后的想法:隐藏异常细节几乎总是不好的。


3
投票

将方法标记为“异步”实际上并不能使其神奇地异步运行。你必须在该方法中使用await

您的代码是同步的,可以在另一个线程中运行它,而无需更改您可以使用的 SendMailAsync 中的签名或代码。但理想情况下,您应该重写 SendMailAsync 以使用 MailSender 的异步 API

var resultTask = Task.Run(async () => await SendMailAsync()); OtherMethod1(); OtherMethod2(); var result = await resultTask;



0
投票


0
投票

但是如果你想让这变得简单,你可以使用 asp.net 中内置的东西。

HostingEnvironment.QueueBackgroundWorkItem((ct) => { SendMailAsync(); }); OtherMethod1(); OtherMethod2();

确保添加对 System.Web.Hosting 的引用

您不需要 SendMailAsync() 来返回任务,因为您不会等待某些事情。只需让电子邮件代码的发送在后台运行即可。

© www.soinside.com 2019 - 2024. All rights reserved.