为什么我的程序在单一语言中运行得更快?

时间:2016-06-09 15:40:58

标签: c# multithreading parallel-processing multiprocessing task-parallel-library

我正在使用TPL学习C#中的多核编程。想出了一个我觉得可以很容易使用的问题,并且可以使用多核来加快速度。但是在运行程序时,我发现单核实现比多核更快。 该死!我错过了什么? 请注意,我使用的是同一台PC。

问题:给定一个数字,找到从0到该数字的所有因子。

我的解决方案:由于我有一个4核CPU,我硬编码我的实现以使用4个任务。任务均匀地分割出数字。如果有100个数字,每个任务每个约25个数字(任务1使用0,4,8,12 ......和任务2使用1,4,9,13 ......)。

这是我的解决方案(它似乎接受的最大输入数字是9999)

public class Factorial
{
    public int TotalNoOfElements { get; set; }

    public BigInteger GetFactorial(BigInteger number)
    {
        if (number == 0)
            return 0;

        if (number == 1)
            return 1;

        return number * GetFactorial(number - 1);
    }

    public BigInteger[] GetFactorialsUsingSingleCore(int number)
    {
        BigInteger[] factorials = new BigInteger[number + 1];

        factorials[0] = 0;
        for (int index = 1; index <= number; index++)
        {
            Factorial f = new Factorial();      //TODO: remove. Throws stackoverflow exception @ GetFactorial() if local method is used directly.
            factorials[index] = f.GetFactorial(index);
        }

        return factorials;
    }

    public BigInteger[] GetFactorialsForNumbers(int[] numbers)
    {
        BigInteger[] factorials = new BigInteger[TotalNoOfElements + 1];
        foreach (int item in numbers)
        {
            Factorial f = new Factorial();      //TODO: remove. Throws stackoverflow exception @ GetFactorial() if local method is used directly.
            factorials[item] = f.GetFactorial(item);
        }
        return factorials;
    }

    public BigInteger[] GetFactorialsUsingMultiCores(int number)
    {
        //int noOfCores = 4;
        StopWatchHelper stopWatchHelper = new StopWatchHelper();
        stopWatchHelper.StartWatch();

        BigInteger[] factorials = new BigInteger[TotalNoOfElements + 1];
        List<int[]> splitNumbersList = SplitNumbersByTasks(number);
        stopWatchHelper.StopWatch();
        stopWatchHelper.ShowElapsedTimeInConsole("Creating list...");

        Task<BigInteger[]> t1 = Task.Factory.StartNew(
                        () =>
                        GetFactorialsForNumbers(splitNumbersList[0])
                        );

        Task<BigInteger[]> t2 = Task.Factory.StartNew(
                        () =>
                        GetFactorialsForNumbers(splitNumbersList[1])
                        );

        Task<BigInteger[]> t3 = Task.Factory.StartNew(
                        () =>
                        GetFactorialsForNumbers(splitNumbersList[2])
                        );

        Task<BigInteger[]> t4 = Task.Factory.StartNew(
                        () =>
                        GetFactorialsForNumbers(splitNumbersList[3])
                        );

        Task[] tasks = { t1, t2, t3, t4 };
        Task.WaitAll(tasks);

        stopWatchHelper.StartWatch();
        //Consolidate result arrays into 1 single array
        foreach (Task<BigInteger[]> task in tasks)
        {
            BigInteger[] result = task.Result;
            for (int index = 0; index < result.Length; index++)
            {
                if(result[index] != 0)
                    factorials[index] = result[index];
            }
        }
        stopWatchHelper.StartWatch();
        stopWatchHelper.ShowElapsedTimeInConsole("Consolidating results...");

        return factorials;
    }

    //Hardcoded for now
    //Returns #ofArrays = InputNumber/TotalTasks such that the work is evenly divided to the Tasks
    //Given an input number, we shall split it evenly across different Tasks.
    //With input as 25, Task 1 gets -> 0, 4, 8, 12, ... and Task 2 gets 1, 5, 9, 13, ...
    List<int[]> SplitNumbersByTasks(int number)
    {
        int noOfCores = 4;
        List<int[]> splitNumbersList = new List<int[]>();

        int reminder = number % noOfCores;
        for (int i = 0; i < noOfCores; i++)
        {
            if (reminder == 0)
            {
                splitNumbersList.Add(new int[(number / noOfCores)]);
            }
            else
            {
                splitNumbersList.Add(new int[(number / noOfCores) + 1]);
                reminder--;
            }
        }

        int arrayIndex = 0;
        for (int index = 1; index <= number; index++)
        {
            splitNumbersList[0][arrayIndex] = index++;
            if (index > number) break;

            splitNumbersList[1][arrayIndex] = index++;
            if (index > number) break;

            splitNumbersList[2][arrayIndex] = index++;
            if (index > number) break;

            splitNumbersList[3][arrayIndex] = index;

            ++arrayIndex;
        }

        return splitNumbersList;
    }
}

助手类:

class StopWatchHelper
{
    Stopwatch stopWatch = new Stopwatch();

    public void StartWatch()
    {
        stopWatch.Reset();
        stopWatch.Start();
    }

    public void StopWatch()
    {
        stopWatch.Stop();
    }

    public void ShowElapsedTimeInConsole(string message)
    {
        Console.WriteLine(message);
        Console.WriteLine(new string('-', message.Length));
        Console.WriteLine("Minutes: " + stopWatch.Elapsed.Minutes);
        Console.WriteLine("Seconds: " + stopWatch.Elapsed.Seconds);
        Console.WriteLine("Milliseconds: " + stopWatch.Elapsed.Milliseconds);
        Console.WriteLine();
    }
}

主要

class Program
{
    static void Main(string[] args)
    {
        int input;
        string strInput;
        bool isNumber;
        StopWatchHelper helper = new StopWatchHelper();

        Factorial factorial = new Factorial();
        //Get input recursively until input is not a number
        do
        {
            strInput = Console.ReadLine();
            Console.WriteLine();

            isNumber = Int32.TryParse(strInput, out input);
            factorial.TotalNoOfElements = input;
            if (isNumber)
            {
                helper.StartWatch();
                BigInteger[] factorialsUsingMultiCore = factorial.GetFactorialsUsingMultiCores(input);
                helper.StopWatch();
                helper.ShowElapsedTimeInConsole("Factorials computed using Multicore");

                helper.StartWatch();
                BigInteger[] factorialsUsingSingleCore = factorial.GetFactorialsUsingSingleCore(input);
                helper.StopWatch();
                helper.ShowElapsedTimeInConsole("Factorials computed using Singlecore");
            }

            Console.WriteLine();

        } while (isNumber);
    }
}

0 个答案:

没有答案