簡體   English   中英

當我們不等待異步方法時會發生什么

[英]What happens when we don't await an async method

我有一個.NET CORE 2后端。 在我的一個控制器端點中,我正在創建要通過電子郵件發送的邀請。 這似乎是端點上的巨大瓶頸,考慮了一下后,我真的不需要等待這些邀請。 如果電子郵件發送失敗,我將無能為力。

如果我不await sendFn()那么它本質上將是一種即發即await sendFn()方法嗎? 我正在閱讀另一個必須執行sendFn().ContinueWith(t => throw(t)) stackoverflow線程,以便能夠捕獲該異常,因為它將在另一個線程中。

我在代碼庫周圍也有類似的郵件發送功能。 它們各自做的事情略有不同,但是我是否可以包裝這些東西以使它們起火而忘記呢? 我認為有些地方我不能使用await (如果可行),但是有些事情會改變數據庫上下文,因此,如果我不等待它們,我可能會遇到某些情況,即某些人正在訪問同一數據庫上下文。

[HttpPost]
public async Task<IActionResult> CreateEvent([FromBody] Event val)
{
    _ctx.Event.Add(val);
    await _ctx.SaveChangesAsync();

    await SendInvitations(val); // fn in question

    return Ok();
}

public async Task SendInvitation(Event event)
{
   forEach (var person in event.people)
   {
     await _ctx.Invitation.Add(person); // This shouldn't happen while another iteration or some other async code elsewhere is using the db ctx.
     _ctx.SaveChangesAsync();
     await _mailService.SendMail(person.email,"you have been invited"); // don't really need to await this.

   }
}

我將有關事件的數據發布到服務器上。 創建事件並將其保存到數據庫后,我將為每個人創建邀請。 這些邀請也是數據庫項。 然后,我發送一封電子郵件。 我最擔心的是,如果我放棄等待,那么在創建邀請時,它可能與其他地方的數據庫上下文或下一次迭代沖突。

為了使您的代碼能夠編譯和運行,我必須進行以下更改:

public async Task<IActionResult> CreateEvent(Event val)
{
    _ctx.Event.Add(val);
    await _ctx.SaveChangesAsync();
    await SendInvitation(val);
    return Ok();
}

public async Task SendInvitation(Event @event)
{
    foreach (var person in @event.people)
    {
        await _ctx.Invitation.Add(person);
        await _ctx.SaveChangesAsync();
        await _mailService.SendMail(person.email, "you have been invited");
    }
}

我還必須編寫以下代碼:

public OK Ok() => new OK();

public class Event
{
    public List<Person> people = new List<Person>();
}

public class Person
{
    public string email;
}

public interface IActionResult { }

public class OK : IActionResult { }

public class Invitation
{
    public Task Add(Person person) => Task.Run(() => { });
}

public static class _ctx
{
    public static List<Event> Event = new List<Event>();
    public static Invitation Invitation = new Invitation();
    public static Task SaveChangesAsync() { return Task.Run(() => { }); }
}

public static class _mailService
{
    public static Task SendMail(string email, string message) { return Task.Run(() => { }); }
}

然后我像這樣更新了SendInvitation

public async Task SendInvitation(Event @event)
{
    Thread.Sleep(2000);
    foreach (var person in @event.people)
    {
        await _ctx.Invitation.Add(person);
        await _ctx.SaveChangesAsync();
        await _mailService.SendMail(person.email, "you have been invited");
    }
    Console.WriteLine("Done `SendInvitation`.");
}

現在,我可以像這樣運行所有程序:

var e = new Event();
e.people.Add(new Person() { email = "foo@bar.com" });
CreateEvent(e).ContinueWith(t => Console.WriteLine("Done `CreateEvent`."));
Console.WriteLine("Done `Main`.");

輸出:

Done `Main`.

然后2秒后:

Done `SendInvitation`.
Done `CreateEvent`.

如果我只是將CreateEvent更改為此:

public async Task<IActionResult> CreateEvent(Event val)
{
    _ctx.Event.Add(val);
    await _ctx.SaveChangesAsync();
    Task.Run(() => SendInvitation(val));
    return Ok();
}

然后我得到以下輸出:

Done `Main`.
Done `CreateEvent`.

然后2秒后:

Done `SendInvitation`.

那似乎就是您想要的。

簡短的答案是您不能保證該代碼的執行將完成。

這就是ASP.NET Core具有用於后台工作的基礎結構的原因: 使用IHostedService和BackgroundService類在.NET Core 2.x webapps或微服務中實現后台任務

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM