我一时糊涂,想不出任何合理的解释。也许这里有人能解释一下。
设置:我有一个类,生成大量的工作项计算与ActionBlock
。在这一点上,确切的实现是不相关的,但只要稍微改变一下,问题就会出现在另一个数据集上。
这是最初的版本
public static class Setups
{
private struct RunData
{
internal MyClass1 Setup;
internal MyClass2 Positions;
internal string Set;
}
private static readonly ActionBlock<RunData> ParallelWorker =
new(d => ProcessSetupsAsync(d.Setup, d.Positions, d.Set),
new ExecutionDataflowBlockOptions
{
BoundedCapacity = Environment.ProcessorCount * 10,
MaxDegreeOfParallelism = Environment.ProcessorCount,
SingleProducerConstrained = false
});
public static async Task GetSetups(ItemType[] bar1Filter,
ItemType[] bar2Filter, bool sameSet)
{
for (/* do some work*/)
{
foreach (RunData rd in MyMethod1(/*variables*/).Select(final
=> new RunData { Positions = positions, Set = set, Setup = final }))
{
if (!await ParallelWorker.SendAsync(rd).ConfigureAwait(false))
{
// Fails after running for about 15 minutes
// with ParallelWorker.Complete is true
throw new Exception("xxxxxxxx");
}
}
}
ParallelWorker.Complete();
await ParallelWorker.Completion.ConfigureAwait(false);
}
private static Task ProcessSetupsAsync
(MyClass1 setup, MyClass2 positions, string set)
{
try
{
List<MyClass1> setups = new();
/* Do some work */
return setups.Count > 0
? LocalAccess.AddSetupAsync(setups)
: Task.CompletedTask;
}
catch (Exception ex)
{
Console.WriteLine(ex); //<-Never gets hit.
throw;
}
我的第一个猜测是被调用方法内部的异常,但这显然不是情况。
我明白了。并行任务确实在数据库中造成了死锁情况。我在查看数据库锁时注意到。
在VS调试器中,我确实看到了将SendAsync调用更改为
后的SQLExceptionsif (!await ParallelWorker.SendAsync(rd).ConfigureAwait(false))
{
await Task.Delay(TimeSpan.FromSeconds(60D)).ConfigureAwait(false);
throw new Exception("Should never happen");
}
并在throw new Exception行设置断点。为什么SqlException没有被try/catch捕获,我不知道。所以现在我很困惑,我对try/catch机制的信仰正在崩溃,但我现在在正确的轨道上。
我可以确认如果我序列化db调用错误消失。我现在正在分析数据库,因为我的印象是,在ROW_LOCK场景中,我的数据写入不应该重叠,另一方面,有一个StoredProcedure使用MERGE,这是已知的问题…
原来的问题解决了,但是为什么try/catch没有捕捉到一个简单的SqlException呢?