我正在玩TPL,并试图通过并行读取和写入同一个词典来找出我可以做多么大的混乱.
所以我有这个代码:
private static void HowCouldARegularDicionaryDeadLock()
{
for (var i = 0; i < 20000; i++)
{
TryToReproduceProblem();
}
}
private static void TryToReproduceProblem()
{
try
{
var dictionary = new Dictionary<int, int>();
Enumerable.Range(0, 1000000)
.ToList()
.AsParallel()
.ForAll(n =>
{
if (!dictionary.ContainsKey(n))
{
dictionary[n] = n; //write
}
var readValue = dictionary[n]; //read
});
}
catch (AggregateException e)
{
e.Flatten()
.InnerExceptions.ToList()
.ForEach(i => Console.WriteLine(i.Message));
}
}
Run Code Online (Sandbox Code Playgroud)
它确实很乱,有很多异常抛出,大多数关于密钥不存在,一些关于索引超出数组的范围.
但运行应用程序一段时间后,它挂起,并且CPU百分比保持在25%,机器有8个核心.所以我假设2个线程满负荷运行.
然后我在上面运行了dottrace,得到了这个:
它符合我的猜测,两个线程以100%运行.
两者都运行Dictionary的FindEntry方法.
然后我用dottrace再次运行应用程序,这次结果略有不同:
这一次,一个线程正在运行FindEntry,另一个正在运行.
我的第一个直觉是它被锁定了,但后来我认为它不可能,只有一个共享资源,而且它没有被锁定.
那怎么解释呢?
ps:我不打算解决问题,可以通过使用ConcurrentDictionary或通过并行聚合来解决.我只是在寻找一个合理的解释.
.net c# parallel-processing multithreading task-parallel-library
如果我注意到哈希表(或构建在哈希表上的任何其他数据结构)正在填满,那么你应该在什么时候构建一个包含更多桶的新表.到目前为止,在表格中给出了n个项目,你如何计算出在新表中使用了多少个桶?
所以假设我有100个桶.当有50个项目时,我应该重组吗?500?5000?或者我应该寻找最完整的桶和关键吗?然后,当我达到这一点时,我有多大的新哈希表?
与此相关的是,如果您事先知道将要进入的项目大小,是否有办法计算桶数以获得良好的平均性能?
我知道真正的答案取决于许多其他考虑因素,例如在特定示例中速度与大小的重要程度,但我正在寻找一般的guildlines.
我也知道我不应该优化这种事情,除非良好的分析表明这是一个瓶颈.我只是在想一个会使用大量哈希表的项目,并想知道如何处理这个问题.