【问题标题】:Why 4 process better than 4 thread?为什么 4 进程优于 4 线程?
【发布时间】:2013-05-14 04:27:16
【问题描述】:
void task1(void* arg) {
    static volatile long res = 1;
    for (long i = 0; i < 100000000; ++i) {
        res ^= (i + 1) * 3 >> 2;
    }
}

4 个线程同时工作,在 30 秒内执行 task1 193 次。但是 4 个进程同时工作,在 30 秒内执行 task1 348 次。为什么会有这么大的差异? 我在 [Mac OS X 10.7.5,Intel Core i5(4 个逻辑核心)] 上对其进行了测试。想想看,Windows 和 Linux 的区别是一样的。

【问题讨论】:

  • 你测试了多少次?它可能会极大地影响您的计算机在后台执行的操作。您可以发布您实例化流程和任务的代码吗?
  • 好吧,static volatile 是否可以跨进程共享?
  • 如果没有static volatile 位,你能做同样的基准测试吗?

标签: c++ multithreading operating-system intel


【解决方案1】:

res 变量是static,这意味着它被同一进程中的所有线程共享。这意味着在四个线程的情况下,一个线程中res 变量的每次修改都必须对其他线程可用,这通常涉及总线上的某种锁定、一级缓存的无效和重新加载在所有其他 CPU 中。

在四个进程的情况下,变量并没有真正被不同的进程共享,所以它们可以真正并行运行,互不干扰。

请注意,主要区别不是线程/进程,而是在一种情况下每个人都访问相同的变量而在另一种情况下他们访问不同的变量这一事实。此外,在线程的情况下,真正的问题不是性能,而是最终结果可能不正确的事实:

res ^= x;

那不是原子操作,处理器会加载res的旧值,然后在寄存器中对其进行修改并写回。如果没有同步原语,多个线程可以加载相同的值,独立修改它并写回变量,在这种情况下,一些线程的工作将被其他线程覆盖。最终结果将取决于不同线程的执行模式,而不是您程序的代码。

要模拟变量的非共享,您需要确保在线程中访问不同的缓存行。最简单的更改是从变量中删除static 限定符,以便每个线程将更新它自己的堆栈中的变量,该变量将位于与其他线程的变量不同的内存地址,并希望映射到不同的缓存线。另一种选择是将四个变量一起创建,但在它们之间添加足够的填充,以便它们分布到不同的缓存行:

struct padded_long {
    volatile unsigned long res;
    char [CACHE_LINE_SIZE - sizeof(long)]; // Find this in your processor documentation
};
void f(void *) {
   static padded_long res[4];
   // detect which thread is running based on the argument and use res[0]..res[3]
   // for the different threads

【讨论】:

    【解决方案2】:

    这是一个进程中所有线程的一个变量:

    static volatile long res = 1;
    

    因此,如果您只在四个进程中的每一个中运行一个线程,那么您就有四种不同的“res”,它们存在于不同的内存位中。在线程的情况下,“res”对于所有四个线程来说都是同一个变量,因此每次更新时,其他三个处理器都必须使其副本无效(删除),并从最后更新的处理器中获取一个新的它。这会减慢一切。如果你真的想为每个线程更新一个变量,我建议你这样做:

    void task1(void* arg) {
        volatile long* res = const_cast<volatile long *>(
               reinterpret_cast<long *>(arg));
        for (long i = 0; i < 100000000; ++i) {
            res ^= (i + 1) * 3 >> 2;
        }
    }
    

    并从不同的内存部分传入不同的long(例如,使用new long 为每个线程生成唯一的地址)。

    【讨论】:

      【解决方案3】:

      线程共享res 变量,因此所有 4 个内核都竞争一个缓存行。不同的进程创建自己的res,从而消除变量竞争。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-01-03
        • 2021-10-12
        • 1970-01-01
        • 2014-06-08
        • 2021-02-14
        • 2011-08-14
        • 1970-01-01
        相关资源
        最近更新 更多