c# - 当我们不等待异步方法时会发生什么

标签 c# asynchronous async-await asp.net-core-2.0

我有一个 .NET CORE 2 后端。在我的一个 Controller 端点中,我正在创建要通过电子邮件发送的邀请。这似乎是端点上的一个巨大瓶颈,在考虑之后,我真的不需要等待这些邀请。如果电子邮件发送失败,我真的无能为力。

如果我不执行 await sendFn() 是否本质上是一个即发即弃的方法?我正在阅读另一个 stackoverflow 线程,我必须执行 sendFn().ContinueWith(t => throw(t)) 才能捕获异常,因为它将在另一个线程中.

我在代码库周围有类似的邮件功能。他们每个人做的事情都略有不同,但是我可以做些什么来包装这些东西,让他们一劳永逸吗?我认为有些地方我不能使用 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`.

Then 2 seconds later:

Done `SendInvitation`.
Done `CreateEvent`.

If I simply change CreateEvent to this:

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`.

这似乎是你想要的。

关于c# - 当我们不等待异步方法时会发生什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51433475/

相关文章:

c# - 带有 net.tcp 的 WCF 错误“服务端点未能监听 URI,因为访问被拒绝

.net - 基于 TcpListener 的应用程序不能很好地扩展

VB.NET:如果我使用 Await 运行 CPU 密集型代码会发生什么情况?

javascript - 异步Javascript : Unexpected result

c# - 没有等待调用的异步/等待

c# - C#生成RSA私钥

C# 使用 Process.Start 参数和路径中的空格

c# - Blazor - 将函数传递给动态组件

iphone - Coredata 更新后一致更新 UITableview

c# - 异步BeginSend方法的使用