dbe*_*eon 3 c# concurrency multithreading entity-framework thread-safety
您好,我需要一些关于 Task.WhenAll() 运行的异步方法的建议。它是 dotnet core 3 项目,上下文和服务被添加为 AddScoped。
当我运行 DoWorksAysnc 方法时,我总是遇到一个问题“在上一个操作完成之前,在此上下文上启动了第二个操作。这通常是由使用同一 DbContext 实例的不同线程引起的。有关如何避免 DbContext 线程问题的更多信息”
我知道 DbContext 不是线程安全的。但我是否可以同时运行 DowksAsync 方法..?
谢谢,
public async Task DoWorksAsync(List<int> ids)
{
if (ids.Count > 0)
{
var listOfTasks = new List<Task>();
foreach(var id in ids)
{
var task = Task.Run(async () => await UpdateDataById(id));
listOfTasks.Add(task);
}
await Task.WhenAll(listOfTasks);
}
}
Run Code Online (Sandbox Code Playgroud)
UpdateDataById 方法是
public async Task UpdateDataById (int id)
{
try
{
//Get products from webservice
List<Product> products = await _searchService.GetItemsByIdAsync(id);
await _dataService.CreateTableIfNotExist(id); //Method inside is await _dbContext.Database.ExecuteSqlRawAsync(string.Format(_sqlCreateTableIfNotExist, id));
// UpdateProductsToDataTable method includes truncate table and bulkcopy.writeToServerAsync(tablename)
//await _dbContext.Database.ExecuteSqlRawAsync(string.Format("Truncate Table {0}", tableName));
//await bulkcopy.WriteToServerAsync();
if (await _dataService.UpdateProductsToDataTable(id,products) == true)
{
await _emailService.sendEmailNotificationAsync();
}
_logService.AddLog("process is done");
_unitOfWork.SaveAsync(); //_context.SaveChangesAsync()
}
catch (Exception ex)
{
await _logService.AddErrorLog(new ErrorLog
{
Id= id,
ErrorMessage = ex.Message
});
_unitOfWork.SaveAsync();
}
}
Run Code Online (Sandbox Code Playgroud)
尽管您知道这一点,但DbContexts它们不是线程安全的,故事结束了..
这个问题很常见,如果您遵循以下经验法则,此修复很简单
DbContext,它们已经在内部缓存了。如果您有一个存储库(我真的建议您不应该这样做),则永远不要将其DbContext作为实例成员,除非您绝对确定它是线程安全的并且它正在非常谨慎地用于小型工作负载。但请参阅第 2 点。DbContext如果可以的话,总是在 using 语句中添加一个DbContext(它们不是线程安全的)。分别参见第1点和第2点如果您确实需要这样做,请DbContext通过一种或另一种方式确保每个线程都是一个单独的实例。
或者按照Jeremy Lakeman的建议。确保每个方法调用的上下文都是唯一的。
| 归档时间: |
|
| 查看次数: |
5948 次 |
| 最近记录: |