use*_*374 0 c# parallel-processing multithreading
我遇到以下代码的问题.代码没有错误,但是当使用并行for循环和常规for循环时,我会收到不同的输出值.我需要使并行for循环正常工作,因为我运行此代码数千次.有谁知道为什么我的并行for循环返回不同的输出?
private object _lock = new object();
public double CalculatePredictedRSquared()
{
double press = 0, tss = 0, press2 = 0, press1 = 0;
Vector<double> output = CreateVector.Dense(Enumerable.Range(0, 400).Select(i => Convert.ToDouble(i)).ToArray());
List<double> input1 = new List<double>(Enumerable.Range(0, 400).Select(i => Convert.ToDouble(i)));
List<double> input2 = new List<double>(Enumerable.Range(200, 400).Select(i => Convert.ToDouble(i)));
Parallel.For(0, output.Count, i =>
{
ConcurrentBag<MultipleRegressionInfo> listMRInfoBag = new ConcurrentBag<MultipleRegressionInfo>(listMRInfo);
ConcurrentBag<double> vectorArrayBag = new ConcurrentBag<double>(output);
ConcurrentBag<double[]> matrixList = new ConcurrentBag<double[]>();
lock (_lock)
{
matrixList.Add(input1.Where((v, k) => k != i).ToArray());
matrixList.Add(input2.Where((v, k) => k != i).ToArray());
}
var matrixArray2 = CreateMatrix.DenseOfColumnArrays(matrixList);
var actualResult = vectorArrayBag.ElementAt(i);
var newVectorArray = CreateVector.Dense(vectorArrayBag.Where((v, j) => j != i).ToArray());
var items = FindBestMRSolution(matrixArray2, newVectorArray);
double estimate1 = 0;
if (items != null)
{
lock (_lock)
{
var y = 0d;
var independentCount = matrixArray2.RowCount;
var dependentCount = newVectorArray.Count;
if (independentCount == dependentCount)
{
var populationCount = independentCount;
y = newVectorArray.Average();
for (int l = 0; l < matrixArray2.ColumnCount; l++)
{
var avg = matrixArray2.Column(l).Average();
y -= avg * items[l];
}
}
for (int m = 0; m < 2; m++)
{
var coefficient = items[m];
if (m == 0)
{
estimate1 += input1.ElementAt(i) * coefficient;
}
else
{
estimate1 += input2.ElementAt(i) * coefficient;
}
}
estimate1 += y;
}
}
else
{
lock (_lock)
{
estimate1 = 0;
}
}
lock (_lock)
{
press1 += Math.Pow(actualResult - estimate1, 2);
}
});
for (int i = 0; i < output.Count; i++)
{
List<double[]> matrixList = new List<double[]>();
matrixList.Add(input1.Where((v, k) => k != i).ToArray());
matrixList.Add(input2.Where((v, k) => k != i).ToArray());
var matrixArray = CreateMatrix.DenseOfColumnArrays(matrixList);
var actualResult = output.ElementAt(i);
var newVectorArray = CreateVector.Dense(output.Where((v, j) => j != i).ToArray());
var items = FindBestMRSolution(matrixArray, newVectorArray);
double estimate = 0;
if (items != null)
{
var y = CalculateYIntercept(matrixArray, newVectorArray, items);
for (int m = 0; m < 2; m++)
{
var coefficient = items[m];
if (m == 0)
{
estimate += input1.ElementAt(i) * coefficient;
}
else
{
estimate += input2.ElementAt(i) * coefficient;
}
}
}
else
{
estimate = 0;
}
press2 += Math.Pow(actualResult - estimate, 2);
}
tss = CalculateTotalSumOfSquares(vectorArray.ToList());
var test1 = 1 - (press1 / tss);
var test2 = 1 - (press2 / tss);
}
public Vector<double> CalculateWithQR(Matrix<double> x, Vector<double> y)
{
Vector<double> result = null;
result = MultipleRegression.QR(x, y);
for (int i = 0; i < result.Count; i++)
{
var value = result.ElementAt(i);
if (Double.IsNaN(value) || Double.IsInfinity(value))
{
return null;
}
}
return result;
}
public Vector<double> CalculateWithNormal(Matrix<double> x, Vector<double> y)
{
Vector<double> result = null;
result = MultipleRegression.NormalEquations(x, y);
for (int i = 0; i < result.Count; i++)
{
var value = result.ElementAt(i);
if (Double.IsNaN(value) || Double.IsInfinity(value))
{
return null;
}
}
return result;
}
public Vector<double> CalculateWithSVD(Matrix<double> x, Vector<double> y)
{
Vector<double> result = null;
result = MultipleRegression.Svd(x, y);
for (int i = 0; i < result.Count; i++)
{
var value = result.ElementAt(i);
if (Double.IsNaN(value) || Double.IsInfinity(value))
{
return null;
}
}
return result;
}
public Vector<double> FindBestMRSolution(Matrix<double> x, Vector<double> y)
{
Vector<double> result = null;
result = CalculateWithNormal(x, y);
if (result != null)
{
return result;
}
else
{
result = CalculateWithSVD(x, y);
if (result != null)
{
return result;
}
else
{
result = CalculateWithQR(x, y);
if (result != null)
{
return result;
}
}
}
return result;
}
public double CalculateTotalSumOfSquares(List<double> dependentVariables)
{
double tts = 0;
for (int i = 0; i < dependentVariables.Count; i++)
{
tts += Math.Pow(dependentVariables.ElementAt(i) - dependentVariables.Average(), 2);
}
return tts;
}
Run Code Online (Sandbox Code Playgroud)
test1 = 137431.12889999992 (parallel for loop)
test2 = 7.3770258447689254E- (regular for loop)
Run Code Online (Sandbox Code Playgroud)
这可能是一个公平的方法来准备一个确实完全可重复的MCVE代码+ A/B/C/... DataSET-s的设置,放在一个可立即运行的[ IDE&Testing Sandbox,这里有超链接] [1 ],社区成员可以单击重新运行按钮并专注于根本原因分析,而不是解码和重新设计不完整SLOC的堆.
如果这是为O/P运行,它将运行其他社区成员,O/P已要求他们给出答案或帮助.
我的新版代码:
public double CalculatePredictedRSquared()
{
Vector<double> output = CreateVector.Dense(Enumerable.Range(0, 400).Select(i => Convert.ToDouble(i)).ToArray());
List<double> input1 = new List<double>(Enumerable.Range(0, 400).Select(i => Convert.ToDouble(i)));
List<double> input2 = new List<double>(Enumerable.Range(200, 400).Select(i => Convert.ToDouble(i)));
double tss = CalculateTotalSumOfSquares(output.ToList());
IEnumerable<int> range = Enumerable.Range(0, output.Count);
var query = range.Select(i => DoIt(i, output, input1, input2));
var result = 1 - (query.Sum() / tss);
return result;
}
public double DoIt(int i, Vector<double> output, List<double> input1, List<double> input2)
{
List<double[]> matrixList = new List<double[]>
{
input1.Where((v, k) => k != i).ToArray(),
input2.Where((v, k) => k != i).ToArray()
};
var matrixArray = CreateMatrix.DenseOfColumnArrays(matrixList);
var actualResult = output.ElementAt(i);
var newVectorArray = CreateVector.Dense(output.Where((v, j) => j != i).ToArray());
var items = FindBestMRSolution(matrixArray, newVectorArray);
double estimate = 0;
if (items != null)
{
var y = CalculateYIntercept(matrixArray, newVectorArray, items);
for (int m = 0; m < 2; m++)
{
var coefficient = items[m];
if (m == 0)
{
estimate += input1.ElementAt(i) * coefficient;
}
else
{
estimate += input2.ElementAt(i) * coefficient;
}
}
}
else
{
estimate = 0;
}
return Math.Pow(actualResult - estimate, 2);
}
Run Code Online (Sandbox Code Playgroud)
Eri*_*ert 12
这整件事是狗的早餐; 你应该完全放弃对并行性的尝试.
重来.这就是我想要你做的.我要你写一个方法DoIt返回double,并采取了INT i和任何其他国家需要做循环的单次迭代.
然后,您将按如下方式重写您的方法:
public double CalculatePredictedRSquared()
{
Vector<double> output = whatever;
// Whatever other state you need here
IEnumerable<int> range = Enumerable.Range(0, output.Count);
var query = range.Select(i => DoIt(i, whatever_other_state));
return query.Sum();
}
Run Code Online (Sandbox Code Playgroud)
得到它了? DoIt是你现在循环的东西.它必须接受i,以及output你需要传递给它的其他任何载体.它必须只计算一个double - 在这种情况下,估计误差的平方 - 并返回该double.
它必须是纯的:它不能读取或写入任何非局部变量,它不能调用任何非纯方法,并且每次给定相同的输入时它必须给出完全相同的结果.纯方法是编写,读取,理解,测试和并行化的最简单方法; 在进行数学计算时总是尝试编写纯方法.
编写测试用例DoIt,然后测试它.这是一种纯粹的方法; 你应该能够编写大量的测试用例.同样地测试所谓的任何纯方法DoIt.
一旦你DoIt对正确和纯洁都感到满意,那么神奇就会发生.只需将其更改为:
range.AsParallel().Select...
Run Code Online (Sandbox Code Playgroud)
然后比较并行和非并行版本.它们应该产生相同的结果; 如果没有,那么有些东西是不纯的.弄清楚它是什么.
然后,验证并行版本更快.如果没有,那么你就没有做足够的工作DoIt来证明并行性; 有关详细信息,请参阅https://en.wikipedia.org/wiki/Amdahl%27s_law.
| 归档时间: |
|
| 查看次数: |
310 次 |
| 最近记录: |