【发布时间】:2015-08-11 23:24:57
【问题描述】:
我是法语,很抱歉首先对不起我的英语。
我在 Visual Studio 上遇到错误(索引超出范围)我只在 Parallel.For 上遇到这个问题。在经典 for 上没有。
我认为一个线程想要访问我的数组 [i] 而另一个线程也想要 ..
这是一个计算 Kmeans 聚类的代码,用于在文档之间建立链接(具有余弦相似度)。
更多信息:
IndexOutOfRange 在similarityMeasure[i]=.....
我有一台带有 2 个处理器(12 个逻辑)的计算机
使用经典 for ,cpu 使用率为 9-14% ,1 次迭代的时间=9min..
使用 parallel.for,cpu 使用率为 70-90% =p,1 次迭代的时间 =~1min30
有时它会在产生错误之前工作更长时间
我的功能是:
private static int FindClosestClusterCenter(List<Centroid> clustercenter, DocumentVector obj)
{
float[] similarityMeasure = new float[clustercenter.Count()];
float[] copy = similarityMeasure;
object sync = new Object();
Parallel.For(0, clustercenter.Count(), (i) => //for(int i = 0; i < clustercenter.Count(); i++) Parallel.For(0, clustercenter.Count(), (i) => //
{
similarityMeasure[i] = SimilarityMatrics.FindCosineSimilarity(clustercenter[i].GroupedDocument[0].VectorSpace, obj.VectorSpace);
});
int index = 0;
float maxValue = similarityMeasure[0];
for (int i = 0; i < similarityMeasure.Count(); i++)
{
if (similarityMeasure[i] > maxValue)
{
maxValue = similarityMeasure[i];
index = i;
}
}
return index;
}
我的函数在这里调用:
do
{
prevClusterCenter = centroidCollection;
DateTime starttime = DateTime.Now;
foreach (DocumentVector obj in documentCollection)//Parallel.ForEach(documentCollection, parallelOptions, obj =>//foreach (DocumentVector obj in documentCollection)
{
int ind = FindClosestClusterCenter(centroidCollection, obj);
resultSet[ind].GroupedDocument.Add(obj);
}
TimeSpan tempsecoule = DateTime.Now.Subtract(starttime);
Console.WriteLine(tempsecoule);
//Console.ReadKey();
InitializeClusterCentroid(out centroidCollection, centroidCollection.Count());
centroidCollection = CalculMeanPoints(resultSet);
stoppingCriteria = CheckStoppingCriteria(prevClusterCenter, centroidCollection);
if (!stoppingCriteria)
{
//initialisation du resultat pour la prochaine itération
InitializeClusterCentroid(out resultSet, centroidCollection.Count);
}
} while (stoppingCriteria == false);
_counter = counter;
return resultSet;
查找CosSimilarity:
public static float FindCosineSimilarity(float[] vecA, float[] vecB)
{
var dotProduct = DotProduct(vecA, vecB);
var magnitudeOfA = Magnitude(vecA);
var magnitudeOfB = Magnitude(vecB);
float result = dotProduct / (float)Math.Pow((magnitudeOfA * magnitudeOfB),2);
//when 0 is divided by 0 it shows result NaN so return 0 in such case.
if (float.IsNaN(result))
return 0;
else
return (float)result;
}
计算均值点:
private static List<Centroid> CalculMeanPoints(List<Centroid> _clust)
{
for (int i = 0; i < _clust.Count(); i++)
{
if (_clust[i].GroupedDocument.Count() > 0)
{
for (int j = 0; j < _clust[i].GroupedDocument[0].VectorSpace.Count(); j++)
{
float total = 0;
foreach (DocumentVector vspace in _clust[i].GroupedDocument)
{
total += vspace.VectorSpace[j];
}
_clust[i].GroupedDocument[0].VectorSpace[j] = total / _clust[i].GroupedDocument.Count();
}
}
}
return _clust;
}
【问题讨论】:
-
哪一行有错误?是
similarityMeasure[i] = ... -
是的 "IndexOutOfRange 是在similarityMeasure[i]=....." :)
-
如果您在 lambda 中使用实际的函数调用而不是匿名方法,那么您应该能够看到 i 中断时的值。这可以帮助您了解有关问题的更多信息。
-
不要在
Parallel.For中使用lock- 按照您的处理方式,Parallel.For的主体永远不能并行执行。您显示的代码没有您报告的问题。请检查该代码是否确实是造成您麻烦的代码。哦,clustercenter.Count()显然会随着时间而变化 - 如果你想坚持你的算法(这似乎不正确),至少将值存储在局部变量中。 -
@Keithin8a 您可以在匿名方法中轻松查看
i的值。至少在 Visual Studio 中是这样的:)
标签: c# multithreading for-loop parallel-processing