我在C#中编写了一个简单的单线程模拟退火算法。
其中一个步骤是在发现此类解决方案时更新最知名的解决方案和相应的成本。
由于模拟退火是一种随机本地搜索,因此在CPU的所有可用内核上运行单独的搜索是有意义的。在这次搜索中,我希望有一个共享最知名的解决方案和相应的成本。偶尔,当一段时间内没有找到好的解决方案时,算法将返回到最知名的解决方案并从那里恢复搜索。我希望所有线程都能回到全球最知名的解决方案。
我知道我可以创建一个单独的类和对象来保存这个值,我知道这肯定会有效,但这对我来说似乎有点麻烦。我怀疑ref
关键字胜利C#在这种情况下会起作用,但我之前从未使用过此关键字,所以我不确定会发生什么。通常我会设置一个测试用例来自己查看,但是由于线程的性质以及算法的高度不可预测的性质,我很难确定发生了什么并确认它是正确的。
所以:
public Solution MultiThreadedSimulatedAnnealing()
{
Solution bestKnownSolution;
double bestKnownSolutionCost;
// ...
Thread[] threads = new Thread[Environment.ProcessorCount];
for (int i = 0; i < threads.Length; i++)
threads[i] = new Thread((ThreadStart)(() =>
{
multiThreadedSAThread(ref bestKnownSolution, ref bestKnownSolutionCost);
}));
foreach (Thread t in threads)
t.Start();
foreach (Thread t in threads)
t.Join();
return bestKnownSolution;
}
调用线程:
private void multiThreadedSAThread(ref Solution bestKnownSolution, ref double bestKnownSolutionCost)
{
// ...
if (cost < bestKnownSolutionCost)
{
bestKnownSolution = solution;
bestKnownSolutionCost = cost;
}
// ...
}
上述方法是否会按我的意图运作?即,子线程中的代码将检查并更新存储在调用函数中的对象,并且调用函数将从所有线程返回总体上的最佳解决方案;因为只有一个最知名的解决方案和成本的副本,在所有子线程和父级之间共享?
(是的,我知道线程可以同时检查和/或覆盖最佳成本,产生不可预测的结果。我会传递一个对象锁定以确保这不会发生;我只是我不想让上面的例子过于复杂化)
谢谢。
答案 0 :(得分:0)
嗯,没有同步,这显然不正确,因为你指出了自己。当您为此添加一致的锁定策略时,它将正常工作。
通过对象引用引用位置或通过ref
(引擎盖下的“托管指针”)之间没有太大区别。
从代码质量的角度来看,将这两个值打包成一个小型DTO类似乎是一种更好的方法。清除ref
混乱和重复。
我还想指出,由于Thread
的使用,代码比需要的更尴尬。通过任务,这将更加清洁。