我有一个小程序,我正在努力提高性能。该程序非常简单,主要基于单个递归函数。然而,它背后的数据集非常大 - 需要大约6,000,000,000次递归,需要大约4-6小时才能运行,具体取决于机器。没有I / O只处理数据,我花了很多时间优化代码并设法找到约60%的改进。
我现在要看的是对代码进行多线程处理,以便利用主机中的所有内核。但是我已经尝试过使用线程,任务和Parellel库中的一些内容,而且我一直无法找到任何不会以负面方式达到性能的内容。
为了让您了解我正在查看的代码类型:
class Program
{
static void Main(string[] args)
{
RecursiveFunction(0);
Console.ReadLine();
}
static void RecursiveFunction(int currentLevel)
{
DoWork(currentLevel);
if (currentLevel < 1000)
for (int i = 0; i < (currentLevel % 6) + 1; i++)
RecursiveFunction(currentLevel + 1);
}
static void DoWork(int currentLevel)
{
Thread.Sleep(42);
}
}
正如您所看到的,该函数的每次运行都不需要很长时间,因此为每次递归创建一个线程的成本是不值得的。递归的每个分支可以具有不同的长度,无法知道每个分支将持续多长时间,因此在特定级别进行线程化不是正确的方法。
有人有任何建议吗?
答案 0 :(得分:2)
在树的上层使用并行性。每次调用都需要几分钟到几小时,因此线程的开销非常小。
使用Parallel.For*
方法并行执行循环。
在递归树的较低层使用正常的顺序循环。
以导致几千个并行循环迭代的方式选择截止水平。
答案 1 :(得分:0)
在不知道申请的情况下很难评论。
对于相同的级别值,会多次调用递归函数。您能否以相同的等级值收获先前运行的结果? ......我猜不是,你可能对副作用感兴趣而不是跑步的结果。
您是否尝试过使用.NET 4.5(VS 2012)TAP?使用async / await,Tasks,您可以尝试使用Task.ContinueWith链接具有相同的递归调用(级别%CORE_COUNT)。 这可能有助于平衡所有任务的负载,从而平衡所有核心。 MSDN : Chain multiple tasks.
我希望你能回复一下适合你的策略。
答案 2 :(得分:0)
您始终可以使用以下代码链接任务,并让任务计划程序安排您的工作。
class Program
{
private static int MaxLevel = 1000;
static void Main(string[] args)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
Task mainTask = ParallelRecursiveFunction(0);
mainTask.Wait();
stopwatch.Stop();
Console.WriteLine("Total time of parallel execution : {0}", stopwatch.ElapsedMilliseconds);
Console.WriteLine("Press Enter to execute the operation sequentially");
Console.WriteLine();
Console.ReadLine();
stopwatch.Reset();
stopwatch.Start();
SequentialRecursiveFunction(0);
stopwatch.Stop();
Console.WriteLine("Total time of sequential execution: {0}",stopwatch.ElapsedMilliseconds);
Console.ReadLine();
}
private static void SequentialRecursiveFunction(int currentLevel)
{
if (currentLevel >= MaxLevel)
return;
DoWork(currentLevel);
SequentialRecursiveFunction(currentLevel +1);
}
public static Task ParallelRecursiveFunction(int currentLevel)
{
if (currentLevel >= MaxLevel)
return _completedTask;
Task t1 = Task.Factory.StartNew(() => DoWork(currentLevel));
Task<Task> t2 = Task.Factory.StartNew(() => ParallelRecursiveFunction(currentLevel + 1));
return Task.Factory.ContinueWhenAll(new Task[] { t1, t2.Unwrap() }, Task.WaitAll);
}
private static Task _completedTask = ((Func<Task>)(() =>
{
var tcs = new TaskCompletionSource<object>();
tcs.SetResult(null);
return tcs.Task;
}))();
static void DoWork(int currentLevel)
{
Console.WriteLine("Do work at level {0}", currentLevel);
Thread.Sleep(42);
}
}
我测试的并行代码比顺序算法快了大约4倍(=我的机器上的处理器数)。
请让我知道您的想法。
干杯。