多线程递归任务

时间:2013-01-04 17:48:48

标签: .net multithreading .net-4.0 task-parallel-library

我有一个小程序,我正在努力提高性能。该程序非常简单,主要基于单个递归函数。然而,它背后的数据集非常大 - 需要大约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);
    }
}

正如您所看到的,该函数的每次运行都不需要很长时间,因此为每次递归创建一个线程的成本是不值得的。递归的每个分支可以具有不同的长度,无法知道每个分支将持续多长时间,因此在特定级别进行线程化不是正确的方法。

有人有任何建议吗?

3 个答案:

答案 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倍(=我的机器上的处理器数)。

请让我知道您的想法。

干杯。