[英]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.