首页 > 解决方案 > 并行处理三个数据库操作

问题描述

我仍在加快异步/等待的速度,我主要将此作为一个学习问题提出。

我有这个方法可以简单地连续创建三个对象。

问题是,这些实际上是并行处理的吗?意思是多线程?

还是每个人实际上都在等待最后一个完成后再开始?

private async Task AddDefaultTasks(Item project)
{
    await this.AddChildAsync(project, "Task A", Enums.ItemTypes.Task);
    await this.AddChildAsync(project, "Task B", Enums.ItemTypes.Task);
    await this.AddChildAsync(project, "Task C", Enums.ItemTypes.Task);
}

private async Task<Item> AddChildAsync(Item parent, string name, Enums.ItemTypes itemType)
{
    return await this.NewAsync(new Item() { Name = name, ParentId = parent.Id, ItemTypeId = (int)itemType });
}

public async Task<Item> NewAsync(Item item)
{
    item.OwnedById = this._applicationUserProvider.CurrentAppUserId;
    item.InsertedBy = item.OwnedById;
    item.UpdatedBy = item.InsertedBy;
    item.EntityStatusId = (int)Enums.EntityStatus.Active;
    DbContext.Items.Add(item);
    await this.SaveChangesAsync();
    return item;
}

有没有更有效的方法来编写异步/等待,比如等待所有?(除了创建所有三个并保存一次的明显方式)。据我了解,EntityFrameworkCore 不支持并行,在这种情况下,我为每个 HttpRequest 使用单个上下文。

标签: c#async-awaitentity-framework-core

解决方案


让我们从基础开始,然后转到特定于 EF 的代码。

问题是,这些实际上是并行处理的吗?意思是多线程?

  1. 不,并行和异步处理不一样。没有什么可以让前面的代码并行运行,实际上都是顺序的。

  2. 不,asyncandawait关键字不创建也不与Threads 一起使用。

作为附加说明,您可以从 中删除asyncawait关键字AddChildAsync,它们不是必需的。

如果您以并行、异步的方式运行代码,您可以:

await Task.WhenAll(
    this.AddChildAsync(project, "Task A", Enums.ItemTypes.Task),
    this.AddChildAsync(project, "Task B", Enums.ItemTypes.Task)
    this.AddChildAsync(project, "Task C", Enums.ItemTypes.Task)
);

这将并行启动和运行所有三个任务。

但是DbContext操作不是线程安全的,上面的代码很可能会严重失败。

有两种方法可以解决这个问题:

  1. AddChildAsyncspawn 成为自己的DbContext. 这将允许您使用我之前提到的并行代码。
  2. 制作另一个AddChildAsync不保存更改的内容,或者使用布尔值来确定是否保存。有了这个,你只会在所有三个实体都添加到上下文之后调用数据库。这虽然是顺序的,但很容易比上述代码的并行处理更快。

推荐阅读