我的代码应该快18倍,但只能快5倍

时间:2019-03-01 21:14:34

标签: c# multithreading task multicore

我试图真正理解这个问题,我现在要问一年。尝试搜索它,阅读有关多核计算的parallel.foreach方法,并提出有关此问题。但是,对于所发生的事情,从来没有一个明确的答案。我一直怀疑没有人真正知道并且只是猜测。

问题:

我的计算机具有24个内核。
我有一个函数:CalculationFunction()

可以测试此代码

现在是我的BIG大问题:
如果我以1个内核运行CalculationFunction()。需要42秒
如果我运行18个核心的CalculationFunction()。花11秒

现在是我的问题,为什么它不快于11秒。如果1核心需要42秒。 18个内核不应该占用: 42/18 =大约或接近2.33秒吗?

这里真正的问题是什么。是否存在瓶颈或实际上没有18个内核参与此过程。有什么不对吗?

重要提示:
我从其他完全相同的测试中知道。我已经打开了同一应用程序的18个实例,并将工作分解为18个部分,并且确实快了18倍。

那么有什么限制应用程序的一个实例不使用我在此代码中分配的全部18个内核的信息吗?

可以测试以下代码:

public void runThreads()
{
    //Change this variable to make tests
    int nrCores = 18; 

    List<List<String>> minusLIST2D = new List<List<String>>(); 
    List<List<String>> plusLIST2D = new List<List<String>>();                
    int nrloops = 3000000;
    nrloops = nrloops / nrCores;

    /*---------------------------------------------------------------*/
    var stopwath = new Stopwatch(); 
    stopwath.Start();
    Task[] tasks = new Task[nrCores];
    for (int i = 0; i < nrCores; i++)
    {
        //Add lists
        minusLIST2D.Add(new List<String>());
        plusLIST2D.Add(new List<String>());

        //Start Task
        int index = i;
        tasks[index] = Task.Factory.StartNew(() => calculationFunction(nrloops, minusLIST2D[index], plusLIST2D[index]));
    }
    Task.WaitAll(tasks); //Wait for all Tasks to complete
    stopwath.Stop(); 
    MessageBox.Show("Elapsec secs: " + stopwath.Elapsed.TotalSeconds.ToString());
}

public void calculationFunction(int nrloops, List<String> minusLIST, List<String> plusLIST)
{
    System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US");

    double num1 = 0; double num2 = 0; double num3 = 0; double number1 = 0; double number2 = 0; double number3 = 0; double thenum1 = 0; double thenum2 = 0; double thenum3 = 0;
    double NUM1 = 0; double NUM2 = 0; double NUM3 = 0; double NUMBER1 = 0; double NUMBER2 = 0; double NUMBER3 = 0; String str = ""; String num11 = ""; String num22 = ""; String num33 = "";
    String number11 = ""; String number22 = ""; String number33 = ""; double calc1 = 0;

    for (int i = 0; i < nrloops; i++)
    {
        //Calculate both calc scenarios!
        num1 = 12.3; number1 = 13.3; thenum1 = 14.3;
        num2 = 12.3; number2 = 13.3; thenum2 = 14.3;
        num3 = 12.3; number3 = 13.3; thenum3 = 14.3;

        NUM1 = num1; NUM2 = num2; NUM3 = num3; NUMBER1 = number1; NUMBER2 = number2; NUMBER3 = number3;
        if (num1 <= 0 || number1 <= 0) { NUM1 = thenum1; NUMBER1 = thenum1; }
        if (num2 <= 0 || number2 <= 0) { NUM2 = thenum2; NUMBER2 = thenum2; }
        if (num3 <= 0 || number3 <= 0) { NUM3 = thenum3; NUMBER3 = thenum3; }
        if (NUM1 > 0 && NUM2 > 0 && NUM3 > 0 && NUMBER1 > 0 && NUMBER2 > 0 && NUMBER3 > 0)
        {
            str = ""; num11 = ""; num22 = ""; num33 = ""; number11 = ""; number22 = ""; number33 = "";
            if (num1 > 0 && num2 > 0 && num3 > 0 && number1 > 0 && number2 > 0 && number3 > 0) { } 
            else { str = string.Format("{0:F10}", thenum1) + " / " + string.Format("{0:F10}", thenum2) + " / " + string.Format("{0:F10}", thenum3); }

            if (num1 <= 0) { num11 = "0"; num1 = thenum1; } else { num11 = string.Format("{0:F10}", num1); }
            if (num2 <= 0) { num22 = "0"; num2 = thenum2; } else { num22 = string.Format("{0:F10}", num2); }
            if (num3 <= 0) { num33 = "0"; num3 = thenum3; } else { num33 = string.Format("{0:F10}", num3); }
            if (number1 <= 0) { number11 = "0"; number1 = thenum1; } else { number11 = string.Format("{0:F10}", number1); }
            if (number2 <= 0) { number22 = "0"; number2 = thenum2; } else { number22 = string.Format("{0:F10}", number2); }
            if (number3 <= 0) { number33 = "0"; number3 = thenum3; } else { number33 = string.Format("{0:F10}", number3); }

            //Calculate
            calc1 = ((num1 * number2 * number3) - 45) / 10;

            //String
            str = calc1 + "," + "ab" + " - " + "ab" + " - " + "ab" + "," +
                  "ab" + " - " + "ab" + " - " + "ab" + "," +
                  num11 + " / " + num22 + " / " + num33 + "," +
                  number11 + " / " + number22 + " / " + number33 + "," +
                  str + "," +
                  calc1 + "%";

            if (calc1 > 0)
            {
                plusLIST.Add(str);
            }
            else
            {
                minusLIST.Add(str);
            }
        }
    }
}

1 个答案:

答案 0 :(得分:3)

  

我总是怀疑没人真正知道并且只是猜测。

好吧,有一些工程师全职致力于研究和设计并行系统。我建议你再想一想。

即使具有该领域的基本学术知识,我也可以告诉您一些事情。

  

如果1个核心需要60秒。 18个核心不应该占用:60/18 =大约   或接近3.33秒?

不,通常不是。可以与这种效率并行的(一类)问题非常少见。即使对于那些实现此级别效率的问题也不是一件容易的事。

首先是阿姆达尔定律。每个问题都有一个串行部分(不能并行化)和一个并行部分。例如,如果只有90%的问题可以并行化,阿姆达尔定律说您可以达到的最大理论速度是10倍。花点时间考虑一下影响。您可以有10、100、1'000'000或无限数量的处理器。对于可并行化90%的问题,您永远无法实现超过10倍的加速。

那只是理论上的限制,假设零开销的完美并行化。

实际上,线程和进程需要一些时间来初始化(这是串行版本中没有的时间)。线程需要同步,因此它们将花费一些时间来等待其他线程。它们之间的任何形式的通信都会产生开销。实际上,加速比阿姆达尔定律给出的理论极限差得多。