c# - 我可以在并行线程中更新一个实体吗?

标签 c# multithreading asp.net-core entity-framework-core abp

使用:Asp.net核心,Entityframework核心,ABP 4.5

我有一个用户注册和初始化流程。但是要花很长时间。我想对此并行化。这是由于从同一实体进行的更新,但是具有不同的字段。

我的目标:
1.端点应尽快做出响应;
2.长初始化在后台处理;

之前的代码(为简洁起见,省略了一些小细节)

public async Task<ResponceDto> Rgistration(RegModel input)
{       
    var user = await _userRegistrationManager.RegisterAsync(input.EmailAddress, input.Password, false );
    var result = await _userManager.AddToRoleAsync(user, defaultRoleName);
    user.Code = GenerateCode();
    await SendEmail(user.EmailAddress, user.Code);
    await AddSubEntities(user);
    await AddSubCollectionEntities(user);
    await CurrentUnitOfWork.SaveChangesAsync();
    return user.MapTo<ResponceDto>();
}

private async Task AddSubEntities(User user)
{
    var newSubEntity = new newSubEntity { User = user, UserId = user.Id };
    await _subEntityRepo.InsertAsync(newSubEntity); 
    //few another One-to-One entities...
}

private async Task AddSubEntities(User user)
{
    List<AnotherEntity> collection = GetSomeCollection(user.Type);  
    await _anotherEntitieRepo.GetDbContext().AddRangeAsync(collection); 
    //few another One-to-Many collections...
}

尝试更改:
public async Task<ResponceDto> Rgistration(RegModel input)
{
    var user = await _userRegistrationManager.RegisterAsync(input.EmailAddress, input.Password, false );

    Task.Run(async () => {
        var result = await _userManager.AddToRoleAsync(user, defaultRoleName);          
    });

    Task.Run(async () => {
        user.Code = GenerateCode();
        await SendEmail(user.EmailAddress, user.Code);  
    });

    Task.Run(async () => {
    using (var unitOfWork = UnitOfWorkManager.Begin())
    {//long operation. defalt unitOfWork out of scope
        try
        {
            await AddSubEntities(user);                            
        }            
        finally
        {                
            unitOfWork.Complete();
        }
    }           
});

Task.Run(async () => {
    using (var unitOfWork = UnitOfWorkManager.Begin())
    {
        try
        {
            await AddSubCollectionEntities(user);                            
        }            
        finally
        {                
            unitOfWork.Complete();
        }
    }           
});
    await CurrentUnitOfWork.SaveChangesAsync();
    return user.MapTo<ResponceDto>();
}

错误:
在这里,我得到了很多与比赛有关的错误。频繁:
  • 在上一个操作完成之前,在此上下文上启动了第二个操作。这通常是由使用相同DbContext实例的不同线程引起的。
  • 在很少的注册调用中:无法在具有唯一索引“YYY”的对象“XXX”中插入重复的键行。重复键值为(70)。该语句已终止。

  • 我认为服务器上的每个请求都在其流中,但显然没有。
  • 或所有用户都已成功注册,但他们在数据库中没有某些子实体。与找出错误的初始化位置=(
  • 相比,不注册用户要容易得多

    如何保持用户实体“打开”进行更新,同时“关闭”其他请求发起的更改?如何使此代码线程安全,快速,任何人都可以提供建议吗?

    最佳答案

    在ASP.NET中使用Task.Run很少是一个好主意。

    异步方法无论如何都在线程池上运行,因此将它们包装在Task.Run中只会增加开销,而没有任何好处。

    在ASP.NET中使用异步的目的仅仅是为了防止线程被阻塞,从而使它们能够处理其他HTTP请求。

    归根结底,数据库是瓶颈。如果所有这些操作都需要在您将响应返回给客户端之前发生,那么除了让它们发生之外,您无能为力。

    如果可以提前返回并允许某些操作在后台继续运行,那么details here显示了如何完成此操作。

    关于c# - 我可以在并行线程中更新一个实体吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61407545/

    相关文章:

    c - 如果一个线程锁定了一个互斥量并且没有解锁它,那么其他线程不应该被阻塞吗?

    c# - ASP.NET Core Identity 3 Cookie 超时

    c# - 如何在单个网站中运行多个 Blazor 应用程序

    c# - 在登录中验证 EMAIL-MVC

    c# - 如何从 Visual Studio 2017 中的 .NET Framework 4.5 控制台应用程序引用 .NET 标准库?

    c# - 使用连接字符串 Entity Framework 在运行时生成 DbContext 和模型

    java - 删除 UI 线程中已发送的消息

    c++ - 如何使用类中的线程操作 vector ?

    c# - 在 Asp Core 中将 IFormFile 转换为图像

    c# - MVC Entity Framework 将一列作为数组