我有这个Parallel.Foreach,当我运行它时只使用20-30%的CPU。 forEach是:
Parallel.ForEach(activePointList, new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }, activePoints =>
{
var nodesCPD = graph.NodesCPDIds.ToDictionary(d => d, d => new List<CostParentDestination>());
var heap = new MinHeapGeneric<KeyValuePair<int, int>>();
foreach (var d in activePoints.Select(a => graph.OldNodes[new KeyValuePair<double, double>(a.XCoord, a.YCoord)]))
{
nodesCPD[d].Add(new CostParentDestination(0, -1, d, -1, 0));
heap.Add(new KeyValuePair<int, int>(d, 0), 0);
}
Calculate(graph.Nodes, nodesCPD, heap, graph.CalculationParams.MaxJourneyCost);
});
正如您所看到的,main函数是Calculate,您可以在此处找到它的实现:
public static void Calculate(
Dictionary<int, MDDNode> nodes,
Dictionary<int, List<CostParentDestination>> nodesCPD,
MinHeapGeneric<KeyValuePair<int, int>> heap,
int maxJourneyCost)
{
while (!heap.Empty())
{
var minItem = heap.PopMinItem();
var currentNodeId = minItem.Key.Key;
int cpdIndex = minItem.Key.Value;
var cpd = nodesCPD[currentNodeId][cpdIndex];
foreach (var edge in nodes[currentNodeId].Edges)
{
var edgeId = edge.Key;
var activeCPD = nodesCPD[edgeId].FirstOrDefault(c => c.ParentId == currentNodeId);
if (activeCPD == null || activeCPD.Met || activeCPD.CostToNearestDestination <= cpd.CostToNearestDestination + edge.Value.Cost) continue;
int zcpdId = -1;
for (int idx = 0; idx < nodesCPD[edgeId].Count; idx++)
if (nodesCPD[edgeId][idx].ParentId == currentNodeId)
zcpdId = idx;
activeCPD.CostToNearestDestination = cpd.CostToNearestDestination + edge.Value.Cost;
activeCPD.DestinationId = cpd.DestinationId;
heap.Add(new KeyValuePair<int, int>(edgeId, zcpdId), cpd.CostToNearestDestination + edge.Value.Cost);
}
cpd.Met = true;
}
}
它读取最小项目然后迭代该点的边缘,过程继续,直到它设置所有点到目的地的距离。
这是堆的Add和PopMinItem方法的实现,我认为这是Calculate()方法的代价很高的部分:
public class MinHeapGeneric<T>
{
public Dictionary<int, T> KeyOfId = new Dictionary<int, T>();
public Dictionary<T, int> IdOfKey = new Dictionary<T, int>();
private readonly MinHeapLite _heap = new MinHeapLite();
private int _id;
public void Add(T key, double value)
{
int id;
if (IdOfKey.ContainsKey(key))
id = IdOfKey[key];
else
{
id = _id++;
KeyOfId.Add(id, key);
IdOfKey.Add(key, id);
}
_heap.Add(new HeapItem(id, value));
}
public KeyValuePair<T, double> PopMinItem()
{
var item = _heap.PopMinItem();
var key = KeyOfId[item.Id];
IdOfKey.Remove(key);
KeyOfId.Remove(item.Id);
return new KeyValuePair<T, double>(key, item.Value);
}
}
public class MinHeapLite
{
private readonly HeapItem[] _items;
private readonly int _maxHeapSize;
private int _lastItemIndex; //Items will start from 1. (root == 1)
private readonly Dictionary<int, int> _idToIndexMap = new Dictionary<int, int>();
public HeapItem PopMinItem()
{
if (Empty())
{
throw (new Exception("Popping from an empty Heap."));
}
HeapItem minItem = new HeapItem(_items[1]);
HeapItem data = _items[_lastItemIndex];
int parentIndex = 1;
int childIndex = parentIndex * 2;
while (childIndex < _lastItemIndex)
{
if (childIndex + 1 < _lastItemIndex && _items[childIndex].Value > _items[childIndex + 1].Value)
childIndex++;
if (_items[childIndex].Value < data.Value)
{
_items[parentIndex] = _items[childIndex];
_idToIndexMap[_items[parentIndex].Id] = parentIndex;
parentIndex = childIndex;
childIndex *= 2;
}
else
break;
}
_items[parentIndex] = data;
_idToIndexMap[_items[parentIndex].Id] = parentIndex;
_lastItemIndex--;
_idToIndexMap.Remove(minItem.Id);
return minItem;
}
}
我的问题是代码的哪一部分阻止主要的Foreach使用整个CPU的电源?