我有一个任务可以为订单生成PDF文件(创建一个PDF大约需要10秒):
public async Task GeneratePDF(Guid Id) {
var order = await
_context
.Orders
.Include(order => order.Customer)
... //a lot more Include and ThenInclude statements
.FirstOrDefaultAsync(order ==> order.Id == Id);
var document = ... //PDF generated here, takes about 10 seconds
order.PDF = document ;
_context.SaveChangesAsync();
}
我尝试了以下操作:
public async Task GenerateAllPDFs() {
var orderIds = await _context.Orders.Select(order=> order.Id).ToListAsync();
foreach (var id in orderIds)
{
_ = GeneratePDF(id).ContinueWith(t => Console.WriteLine(t.Exception), TaskContinuationOptions.OnlyOnFaulted);
}
}
这给了我错误:
System.ObjectDisposedException:无法访问已处置的对象。导致此错误的常见原因是,处理从依赖项注入中解决的上下文,然后稍后尝试在应用程序中的其他位置使用相同的上下文实例。如果在上下文上调用Dispose()或将上下文包装在using语句中,则可能会发生这种情况。如果您正在使用依赖项注入,则应让依赖项注入容器来处理上下文实例。
如果我按以下方式更改任务...
public async Task GenerateAllPDFs() {
var orderIds = await _context.Orders.Select(order=> order.Id).ToListAsync();
foreach (var id in orderIds)
{
_ = await GeneratePDF(id);
}
}
...它按顺序运行每个订单的任务,需要花很多时间才能完成(我有数千个订单,每个订单大约需要10秒)...
如何在上下文中针对所有订单并行运行此任务,以使完成时间比顺序处理少得多?
答案 0 :(得分:2)
您可以将订单ID映射到任务并等待它们,例如:
public async Task GeneratePDF(Order order) {
var document = ... //PDF generated here, takes about 10 seconds
order.PDF = document ;
}
public async Task GenerateAllPDFs() {
var orderIds = await _context.Orders.ToListAsync();
var tasks = orderIds.Select((order) => GeneratePDF(order).ContinueWith(t => Console.WriteLine(t.Exception), TaskContinuationOptions.OnlyOnFaulted));
await Task.WhenAll(tasks);
await _context.SaveChangesAsync();
}
答案 1 :(得分:1)
这是我从评论中提出的建议作为答案。我将其分为三个部分:
1)获得所有订单,
2)然后执行Parallel.Foreach并行生成所有文档。并按正确顺序分配每个文档,最后
3)进行一次_context.SaveChangesAsync();
来对服务器上的数据进行批量更新
public async Task GenerateAllPDFs()
{
var allOrders = await _context.Orders.ToListAsync();
System.Threading.Tasks.Parallel.ForEach(allOrders, order =>
{
var document = ... //PDF generated here, takes about 10 seconds
order.PDF = document ;
});
await _context.SaveChangesAsync();
}
答案 2 :(得分:0)
您需要实现并行编程。
Private Sub Form_Load()
Dim db As DAO.Database
Dim qdfSelectQuery As DAO.queryDef
Dim argumentsStringArray() As String
If Len(Me.OpenArgs) > 0 Then
argumentsStringArray = Split(Me.OpenArgs, "|")
…...Blah blah initialize some variables using the argumentsStringArray Blah blah …..;
End If
End Sub
答案 3 :(得分:0)
我想我必须“复制” GeneratePDF
方法以通过实现其他答案来方便进行批处理,因为我也需要在非批处理模式下使用此方法...