【问题标题】:Async Programming without Await?没有等待的异步编程?
【发布时间】:2015-10-02 16:16:01
【问题描述】:

我正在研究一系列使用实体框架执行许多不同数据库调用的方法。其中许多方法可以异步运行,因为我真的不关心它们的输出,也不依赖它们。

但是,当我尝试实现某些方法时,我收到了来自编译器的警告:“由于未等待此调用,因此当前方法在调用完成之前继续运行”

但对我来说,这似乎是我想要的行为,因为我不在乎方法的作用。

这里是方法的一个例子

public async Task SetupAccessControl(int objectTypeId, int objectId, int? organizationId)
{
    using (var context = new SupportContext(CustomerId))
    {
        ... // omitted for brevity
        if (objectTypeId == (int) ObjectType.User)
        {
            AddToUserRoleBridge("Everyone", objectId);//Warning on this line
            AddToUserRoleBridge("Default", objectId); //Warning on this line
        }
        ... // omitted for brevity
    }
}

public async Task AddToUserRoleBridge(string role, int userId)
{
    using (var context = new SupportContext(CustomerId))
    {
        var defaultRole = context.Roles.FirstOrDefault(n => n.Name == role);
        if (defaultRole != null)
        {
            var urb = new UserRoleBridge
            {
                RoleId = defaultRole.Id,
                UserId = userId
            };

            context.UserRoleBridges.Add(urb);
            await context.SaveChangesAsync();
        }
    }
} 

编辑

本质上,当我运行 main 函数时,我希望一系列方法调用同时触发并在它们自己的线程中处理所有内容,这样我就不必担心它了。这是一个伪代码示例。

public async void RunAllAsync() {
    taskA(*some value*);
    taskA(*some value*);
    taskB(*some value*);
    taskB(*some value*);

    await AllTasksCompleted
}

public async Task taskA(int item){
     //do something with item
}


public async Task taskB(int item) {
    subTaskB(*some value*)
    subTaskB(*some value*)
}

public async Task subTaskB(int item) {
    // do something
} 

在上面的示例中,当调用#RunAllAsync 时,它进行的每个函数调用(以及它们进行的函数调用)都会同时触发。当所有这些调用都完成后,任何名为#RunAllAsync 的方法都将继续执行。

【问题讨论】:

  • 看看这个:msdn.microsoft.com/en-us/library/… 有一个很好的图表展示了异步方法是如何运行的。
  • 您的程序在任务完成之前终止时是否仍然正确执行?如果出现一个你永远不会看到的异常,它会失败吗?这些问题的正确答案几乎总是响亮的noRead this.
  • as I don't care what the methods do 真的吗?你确定吗?你不在乎他们什么时候完成?你不在乎是否他们完成了吗?你不在乎他们是否抛出异常?虽然真正的“即发即弃”场景可能发生,但它比大多数人想象的要少。
  • 我忽略了每个函数的全部内容。但是,每个函数中都有错误处理程序来检查是否完成。他们还将所有内容记录在审计跟踪中,以便可以监控所有内容。说我不在乎这些方法做了什么,我只是说我不想 await 我所做的任何调用,因为我只是希望它们都同时运行。
  • 我用一些简单的伪代码更新了我的主要帖子,这些伪代码在一定程度上说明了我正在尝试做的事情。

标签: c# entity-framework asynchronous


【解决方案1】:

如果您不使用await,则async 关键字实际上并没有什么用处,您可以将其关闭。无论是否标记为异步,您都可以等待返回 Task 的方法。

public Task DoSomethingAsync()
{
    Task someTaskJustLikeANormalReturnValue = Task.Delay(1000);
    return someTaskJustLikeANormalReturnValue;
}

// later...
public async Task SomeOtherFunction()
{
    // You can await DoSomethingAsync just like any async method, because
    // you're really awaiting the Task which got returned.
    await DoSomethingAsync();
}

在你的情况下,我可能会收集任务并一起等待它们:

    public async Task SetupAccessControl(int objectTypeId, int objectId, int? organizationId)
    {
        var tasks = new List<Task>();
        using (var context = new SupportContext(CustomerId))
        {
            ... // omitted for brevity
            if (objectTypeId == (int) ObjectType.User)
            {
                tasks.Add(AddToUserRoleBridge("Everyone", objectId));
                tasks.Add(AddToUserRoleBridge("Default", objectId));
            }
            ... // omitted for brevity
        }

        await Task.WhenAll(tasks.ToArray());
    }

这允许您将是否等待子任务的决定传递给调用者。如果它们发生在AddToUserRoleBridge 中,这也将允许任何调用者解开任何异常。

【讨论】:

  • "async 关键字的唯一作用是启用 await 关键字。"嗯,不是真的。它还改变了异常的传播方式,以及返回值的包装方式。
  • 没错,我重写了第一句话,使其更准确,更贴近问题。
  • 第一句话仍然不正确。考虑:public Task Foo() {} 不会编译。 public async Task Foo() {} 将。
  • 那么在我的原始帖子中的代码示例中,构建它们以使其异步运行的正确方法是什么?
  • 请注意,如果您将问题中的第二种方法从使用await context.SaveChangesAsync(); 更改为return context.SaveChangesAsync(),它会中断(或更糟,有时会中断),因为它不是真正的尾调用,因为它调用@ 987654331@(通过usingawait之后。
【解决方案2】:

你可以通过两种方式做到这一点:

  • 更改 AddToUserRoleBridge 的签名以返回 void will 删除警告(但没有什么可以等待它)。
  • 存储调用结果。 var ignoreme=AddToUserRoleBridge(...) 也会删除警告。

【讨论】:

  • 虽然这确实回答了你的问题,但我强烈推荐 Erik 的回答,而不是这样做。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-04-15
  • 2015-09-28
  • 1970-01-01
  • 2012-08-12
  • 2013-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多