fork()Vs Thread的公平比较

Mar*_*ork 23 c c++ unix multithreading fork

我正在讨论fork()Vs thread()相对于任务并行化的相对成本.

我们了解进程Vs Thread之间的基本区别

线:

  • 易于在线程之间进行通信
  • 快速上下文切换.

流程:

  • 容错.
  • 与父母沟通不是真正的问题(打开管道)
  • 与其他子流程的沟通很难

但我们不同意流程Vs线程的启动成本.
因此,为了测试理论,我编写了以下代码.我的问题:这是衡量启动成本的有效测试,还是我遗漏了一些东西.此外,我对每个测试在不同平台上的表现感兴趣.

fork.cpp

#include <boost/lexical_cast.hpp>
#include <vector>
#include <unistd.h>
#include <iostream>
#include <stdlib.h>
#include <time.h>

extern "C" int threadStart(void* threadData)
{
    return 0;
}

int main(int argc,char* argv[])
{
    int threadCount =  boost::lexical_cast<int>(argv[1]);

    std::vector<pid_t>   data(threadCount);
    clock_t                 start   = clock();
    for(int loop=0;loop < threadCount;++loop)
    {
        data[loop]  = fork();
        if (data[looo] == -1)
        {
            std::cout << "Abort\n";
            exit(1);
        }
        if (data[loop] == 0)
        {
            exit(threadStart(NULL));
        }
    }
    clock_t                 middle   = clock();
    for(int loop=0;loop < threadCount;++loop)
    {
        int   result;
        waitpid(data[loop], &result, 0);
    }
    clock_t                 end   = clock();

   std::cout << threadCount << "\t" << middle - start << "\t" << end - middle << "\t"<< end - start << "\n";
}
Run Code Online (Sandbox Code Playgroud)

Thread.cpp

#include <boost/lexical_cast.hpp>
#include <vector>
#include <iostream>
#include <pthread.h>
#include <time.h>


extern "C" void* threadStart(void* threadData)
{
    return NULL;
}   

int main(int argc,char* argv[])
{
    int threadCount =  boost::lexical_cast<int>(argv[1]);

    std::vector<pthread_t>   data(threadCount);

    clock_t                 start   = clock();
    for(int loop=0;loop < threadCount;++loop)
    {
        if (pthread_create(&data[loop], NULL, threadStart, NULL) != 0)
        {
            std::cout << "Abort\n";
            exit(1);
        }
    }   
    clock_t                 middle   = clock();
    for(int loop=0;loop < threadCount;++loop)
    {   
        void*   result;
        pthread_join(data[loop], &result);
    }
    clock_t                 end   = clock();

   std::cout << threadCount << "\t" << middle - start << "\t" << end - middle << "\t"<< end - start << "\n";

}
Run Code Online (Sandbox Code Playgroud)

我希望Windows在流程创建方面做得更糟.
但我希望现代的Unix系统具有相当轻的分叉成本,至少可以与线程相媲美.在较旧的Unix风格的系统上(在fork()之前实现为在写页面上使用副本),它会更糟糕.

无论如何我的时间结果是:

> uname -a
Darwin Alpha.local 10.4.0 Darwin Kernel Version 10.4.0: Fri Apr 23 18:28:53 PDT 2010; root:xnu-1504.7.4~1/RELEASE_I386 i386
> gcc --version | grep GCC
i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5659)
> g++ thread.cpp -o thread -I~/include
> g++ fork.cpp -o fork -I~/include
> foreach a ( 1 2 3 4 5 6 7 8 9 10 12 15 20 30 40 50 60 70 80 90 100 )
foreach? ./thread ${a} >> A
foreach? end
> foreach a ( 1 2 3 4 5 6 7 8 9 10 12 15 20 30 40 50 60 70 80 90 100 )
foreach? ./fork ${a}  >> A
foreach? end
vi A 

Thread:                             Fork:
C   Start   Wait    Total           C   Start   Wait    Total
==============================================================
 1    26     145     171             1   160     37      197
 2    44     198     242             2   290     37      327
 3    62     234     296             3   413     41      454
 4    77     275     352             4   499     59      558
 5    91     107   10808             5   599     57      656
 6    99     332     431             6   665     52      717
 7   130     388     518             7   741     69      810
 8   204     468     672             8   833     56      889
 9   164     469     633             9  1067     76     1143
10   165     450     615            10  1147     64     1211
12   343     585     928            12  1213     71     1284
15   232     647     879            15  1360    203     1563
20   319     921    1240            20  2161     96     2257
30   461    1243    1704            30  3005    129     3134
40   559    1487    2046            40  4466    166     4632
50   686    1912    2598            50  4591    292     4883
60   827    2208    3035            60  5234    317     5551
70   973    2885    3858            70  7003    416     7419
80  3545    2738    6283            80  7735    293     8028
90  1392    3497    4889            90  7869    463     8332
100 3917    4180    8097            100 8974    436     9410
Run Code Online (Sandbox Code Playgroud)

编辑:

做一个1000个孩子导致fork版本失败.
所以我减少了孩子的数量.但是进行单一测试似乎也不公平,所以这里有一系列价值观.

and*_*coz 11

咕... ...我不喜欢你的解决方案有很多原因:

  1. 您没有考虑子进程/线程的执行时间.

  2. 你应该比较cpu-usage而不是经过的时间.这样,您的统计信息将不会依赖于磁盘访问拥塞.

  3. 让您的孩子进行一些事情.请记住,"modern"fork使用copy-on-write机制来避免在需要之前为子进程分配内存.立即退出太容易了.这样你就可以避免fork的所有缺点.

  4. CPU时间不是您需要考虑的唯一成本.内存消耗和IPC的缓慢都是fork解决方案的缺点.

您可以使用"rusage"而不是"clock"来衡量实际资源使用情况.

PS我认为你不能真正衡量编写简单测试程序的进程/线程开销.有太多因素,通常,线程和进程之间的选择是由除了cpu使用之外的其他原因驱动的.

  • 您是否需要CPU时间或待机时间取决于您是否尝试使用较少的CPU周期或只是尽快完成某些操作.并行化时,您不能期望使用更少的周期,因此您可能只关心更快地完成某些事情,这意味着墙上时间是正确的测量. (2认同)