我有一个PLINQ查询......
batch
.AsParallel()
.WithExecutionMode(ParallelExecutionMode.ForceParallelism)
.WithCancellation(cancellationToken);
.Select(i => new { instruction = i, accountKey = new AccountKey(i.x, i.y, i.z) })
.GroupBy(x => x.accountKey)
.ForAll(grouping =>
{
foreach (var instructionBatch in grouping.OrderBy(i => i.instruction.FileRow).Select(i => i.instruction))
{
// High CPU method.
}
});
在批处理中,可以有10,000条记录。这些调用高CPU方法,这反过来调用Web服务并将信息保存到数据库。
在我的物理64位PC i7-4770 CPU @ 3.40 GHz 16.0GB内存上。运行此代码的服务将启动大约32个线程,并占用大约150,000 - 200,000 KB内存。
在Hyper-V测试环境中,这是一个64位虚拟机E5-2630 v3 @ 2.40GHz,它可以生成超过200个线程,内存命中率接近2GB限制。
是否有任何理由为什么它会激活这么多线程以及为什么虚拟机上没有释放内存?
我是否需要使用WithDegreeOfParallelism。如果可以使用4个不同的批次(1 x 1记录,1 x 100记录,1 x 1000和1 x 10,000)同时调用此过程,这是否意味着如果我指定WithDegreeOfParallelism,则每个批次将使用该批次触发4个批次线程数,甚至是1个记录的批次?
感谢您的帮助。
答案 0 :(得分:1)
TPL Parallel
和PLINQ设施不擅长处理IO。他们倾向于选择糟糕的线程数。这些方法使用的线程计数是启发式驱动的。我相信它是包含这种启发式的线程池。
当IO在播放时,我强烈建议使用WithDegreeOfParallelism
。您可以使用Environment.ProcessorCount
。如果涉及IO,您可能希望略微过度订阅并添加一定量的线程。
在PLINQ中WithDegreeOfParallelism
是绝对数量。不多也不少。所以是的,4个并发查询导致4个线程数。我相信内置的自动线程计数启发式不会发生这个问题。
考虑对所有并发查询使用固定并发TaskScheduler
。
以下是一项实验:使用Thread.Sleep(1000000)
运行该循环。你会发现很多线程。可能是每500毫秒一个。当它认为需要更多线程以避免死锁并提高利用率时,这是注入线程的线程池方式。完全不适合IO。
答案 1 :(得分:0)
最后,在whist运行性能监视器中,我注意到在虚拟化环境中,Exceps Thrown / Sec的perf计数器#显示了非常高的数字。我跟着http://blogs.msdn.com/b/spike/archive/2011/06/23/how-to-figure-out-what-exception-is-causing-a-high-number-in-of -exceps-thrown-sec-using-procdump-and-windbg.aspx并确定在尝试连接到mysql数据库时抛出了未处理的异常。这是因为防火墙规则没有到位。
关于并行性。正在开始高级CPU方法的第二次火灾和遗忘任务,以生成字母。但事实并非如此 围绕它的任何异常/日志处理。这就是抛出错误的地方。为了解决这个问题,我将await Task.Run包装在try catch中。