为什么我将1个CPU绑定到比多个CPU执行得快得多的多线程程序中?

时间:2018-11-01 04:42:31

标签: c# multithreading

我正在编写一个测试程序来启动两个线程,如下所示。

当我使用Process.ProcessorAffinity绑定来限制仅使用1个CPU时,该程序需要执行45.8683742秒的时间,而CPU 2几乎不需要时间在此处使用操作系统内核程序。

1CPU usage of 1CPU in Task Manager

当我使用Process.ProcessorAffinity绑定来限制仅使用2个CPU时,该程序需要执行67.733864秒,而CPU 1,2则几乎不需要时间在这里使用操作系统内核程序。

2 CPUs usage of 1CPU in Task Manager

当我使用Process.ProcessorAffinity绑定来限制仅使用3个CPU时,该程序将执行116.8519694秒,而它们所占用的CPU 1,2,3将使用更多时间的操作系统内核程序。

3 CPUs usage of 1CPU in Task Manager

当我使用Process.ProcessorAffinity绑定来限制仅使用8个CPU时,该程序将花费132.9382714秒来执行,并且它们所占用的所有CPU都将花费更多的时间来使用操作系统内核程序。

4 CPUs usage of 1CPU in Task Manager

我不知道发生了什么,有人可以帮忙解释一下吗?

    class Program
{
    private static long counter = 0;
    public static void Main()
    {
        //Process.GetCurrentProcess().ProcessorAffinity = (IntPtr)7;

        Thread thread1 = new Thread(MyMethod);
        Thread thread2 = new Thread(MyMethod);

        thread1.Start();
        thread2.Start();

        Stopwatch sw = new Stopwatch();
        sw.Start();

        thread1.Join();
        thread2.Join();

        sw.Stop();

        Console.WriteLine($"Sum is {counter}");
        Console.WriteLine($"Total is {sw.Elapsed.TotalSeconds} Sec");

        Console.WriteLine("Press any key for continuing...");
        Console.ReadKey();
    }

    private static void MyMethod()
    {
        for (int index = 0; index < int.MaxValue; index++)
        { Interlocked.Increment(ref counter); }
    }
}

1 个答案:

答案 0 :(得分:2)

根据您的评论,您试图通过该计数器强制出现竞争状态。这里的问题是每个CPU都有一层层的缓存。

虽然CPU和运行时不能保证没有没有竞争条件,但至少最好不要主动导致。几乎没有什么东西可以使它们快到3层缓存中的任何一层都不同步。

例如,如果核心1更改了其第1层缓存中的counter值,则该更改将被有效地传播到第3层缓存-然后传播到每个核心的第1层缓存中。

由于操作为counter = counter + 1,因此仍然存在争用条件的空间。虽然您假设该操作将完全受CPU限制,但刷新缓存实际上会强制将其限制为内存。