递归函数使用PLINQ计算阶乘

时间:2012-12-02 03:42:00

标签: c# recursion parallel-processing task-parallel-library

注意我很清楚我在问什么,并且我无法在正常情况下使用这样的功能,但它被用作研究我正在进行的因子实验研究生项目的因素。

我有以下功能,我想使用PLINQ(非TPL)运行。我知道PLINQ在TPL之上运行,但这部分实验。另外,除非我不知道用PLINQ做另一种方式,我相信我必须在某种程度上“破解”使用带递归的for循环的阶乘方法。

由于Parallel类只提供For,ForEach和Invoke,它不提供我需要的东西,例如TPL做什么,我需要它返回,而Invoke不会这样做,所以我将不得不使用For和do每次递归调用从0开始的for循环(是的,我知道它看起来很荒谬)。

我想做以下事情:

public ulong RecursivePLINQ(ulong factor)
    {
        if (factor > 1)
        {
            Parallel.For<ulong>(0, 1, () => factor, (j, loop, factorial) =>
            {
                Thread.Sleep(1);    /*Simulate Moderate Operation*/
                return factorial * RecursivePLINQ(--factorial);
            }, (i) => { });
        }


        return 1;

    }

目前,正在发生的事情似乎正在起作用,但在最后的调用中它返回1,并且递归调用的结果是1,而不是递归更改的值。我似乎无法遇到什么问题。我在这里显示了备用TPL实现(再次用于研究),这是有效的。

public ulong RecursiveTPL(ulong factor)
    {
        if (factor > 1)
        {
            Task<ulong> task = new Task<ulong>((f) =>
            {
                Thread.Sleep(1);    /*Simulate Moderate Operation*/
                ulong val = (ulong)f;
                return factor * RecursiveTPL(--val);
            }, factor);
            task.Start();
            task.Wait();
            return task.Result;
        }
            return 1;


    }

*** 请不要因为我的要求而激怒我,这是一个非常具体的研究目的 * ****

编辑我在MSDN文档上看到了一个示例,它显示了线程局部变量的使用,所以我尝试了类似的东西,但我的头开始旋转一点......不要注意铸造,它只是为了看我是否可以让它工作......

public ulong RecursivePLINQ(ulong factor)
    {
        long total = 0;
        if (factor > 1)
        {
            Parallel.For<ulong>(0, 1, () => factor, (j, loop, factorial) =>
            {
                Thread.Sleep(1);    /*Simulate Moderate Operation*/
                return factorial * RecursivePLINQ(--factorial);
            }, (i) =>  Interlocked.Add(ref total,(long)i)
            );
        }


        return (ulong)total;

    }

2 个答案:

答案 0 :(得分:2)

它不漂亮,我真的不确定这对我的目的是否有效,但它确实给了我正确的因子。我得到了这个解决方案,但是我必须对总参数进行校正以使其工作,不确定我会称之为什么,或者是否有更好的方法来实现它,但现在必须这样做。 ..

public long RecursivePLINQ(long factor,long total)
    {

        if(total == 0)
        {
            total = 1;
        }
        if (factor > 1)
        {
            Parallel.For<long>(0, 1, () => factor, (j, loop, factorial) =>
            {
                Thread.Sleep(1);    /*Simulate Moderate Operation*/
                total = factorial * RecursivePLINQ(--factorial, total);
                return total;
            }, (i) =>  {return;});
        }
        return total;
    }

答案 1 :(得分:1)

this Dr Dobbs article无耻地复制,您可以使用聚合扩展方法来计算阶乘:

int value=5; 
var factorial=Enumerable.Range(1, value).AsParallel()
             .Aggregate(1, (result, number)=>      
                           result*number, result=>result);

您可以争辩说Aggregate会执行您手动执行的递归,或者您可以编写递归调用自身来计算阶乘的代码。

然而,和其他人一样,我看不到你会完成什么。你的代码将由PLINQ的设置和拆卸主导,你得到的任何数字都将毫无意义。

如果有的话,PLINQ用于使用一系列可以并行执行的运算符来替换循环代码,而程序员不必指定这将如何发生。