Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ fork()与Thread的公平比较_C++_C_Multithreading_Unix_Fork - Fatal编程技术网

C++ fork()与Thread的公平比较

C++ fork()与Thread的公平比较,c++,c,multithreading,unix,fork,C++,C,Multithreading,Unix,Fork,我在讨论fork()与thread()在任务并行化方面的相对成本 我们理解进程与线程之间的基本区别 线程: 易于在线程之间通信 快速上下文切换 过程: 容错性 与家长沟通不是真正的问题(打开管道) 与其他子进程的通信困难 但我们在进程与线程的启动成本方面存在分歧。 为了测试这些理论,我编写了以下代码。我的问题是:这是衡量启动成本的有效测试,还是我遗漏了什么。此外,我还对每个测试在不同平台上的执行方式感兴趣 fork.cpp 编辑: 执行1000个子项的操作导致fork版本失败。 所以我减

我在讨论fork()与thread()在任务并行化方面的相对成本

我们理解进程与线程之间的基本区别

线程:

  • 易于在线程之间通信
  • 快速上下文切换
过程:

  • 容错性
  • 与家长沟通不是真正的问题(打开管道)
  • 与其他子进程的通信困难
但我们在进程与线程的启动成本方面存在分歧。
为了测试这些理论,我编写了以下代码。我的问题是:这是衡量启动成本的有效测试,还是我遗漏了什么。此外,我还对每个测试在不同平台上的执行方式感兴趣

fork.cpp 编辑: 执行1000个子项的操作导致fork版本失败。

所以我减少了孩子的数量。但是做一个单独的测试似乎也不公平,所以这里有一个值范围。

在Linux下
fork
是对
sys\u clone
的一个特殊调用,无论是在库中还是在内核中。Clone有很多开关可以打开和关闭,每个开关都会影响启动的成本


实际的库函数
clone
可能比
fork
更昂贵,因为它做的更多,尽管大部分都在子端(堆栈交换和通过指针调用函数)。

咕哝。。。我不喜欢您的解决方案,原因有很多:

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

  • 您应该比较cpu使用率,而不是光秃秃的运行时间。这样,您的统计数据将不受磁盘访问拥塞等因素的影响

  • 让你的孩子做点什么。请记住,“现代”fork使用写时复制机制,以避免在需要之前将内存分配给子进程。立即退出太容易了。这样你就完全避免了叉子的所有缺点

  • CPU时间不是您必须考虑的唯一成本。内存消耗和工控机速度慢都是fork解决方案的缺点

  • 您可以使用“rusage”而不是“clock”来衡量实际资源使用情况


    另外,我认为编写一个简单的测试程序并不能真正衡量进程/线程开销。有太多的因素,通常情况下,线程和进程之间的选择是由其他原因驱动的,而不仅仅是cpu的使用。

    微基准测试表明,线程创建和连接(我写这篇文章时没有分叉结果)需要数十或数百微秒(假设您的系统的时钟为每秒1000000个,因为这是XSI要求,所以它可能有)

    既然你说fork()的开销是线程的3倍,那么我们现在讨论的最坏的情况仍然是十分之一毫秒。如果这在应用程序中是显而易见的,那么你可以使用进程/线程池,就像Apache 1.3那样。在任何情况下,我都会说启动时间是没有意义的


    线程与进程(在Linux和大多数Unix上)的重要区别在于,在进程上,您可以使用IPC、共享内存(SYSV或mmap样式)、管道、套接字(您可以通过AF_Unix套接字发送文件描述符,这意味着您可以选择要共享的fd),…而在线程上,几乎所有内容都是默认共享的,无论是否需要共享。事实上,这就是Plan 9拥有rfork()和Linux拥有clone()(以及最近的unshare())的原因,因此您可以选择共享什么。

    看看这个关于线程和进程在性能方面的不同的答案:很难看出这是一个有意义的测试。您还没有做任何事情来衡量设置fork所需通信的成本。fork和thread之间的选择是(几乎?)从不受性能驱动。功能完全不同;驱动因素是“你想做什么?”@汉斯·帕桑特:说得对。不幸的是,这变得非常具体。有什么建议吗?我只是想表明,在选择是否使用线程/进程时,启动成本不是一个因素。@Matt Joiner:在选择使用线程/进程时,这些都是值得考虑的理由。我正在尝试(尚未成功)创业成本不是影响你决策的因素(差别很小,其他因素更重要)。最后,这是我的论点。创建线程或进程的成本差异是由使用情况的许多因素决定的。但创建子线程或进程的成本不应该是这些因素之一,因为差异如此之小。您想要的是CPU时间还是墙时间取决于您是尝试使用更少的CPU周期,还是仅仅使用更少的CPU周期方法做得更快。当并行化时,你不能期望使用更少的周期,所以你可能只关心更快地完成一些事情,这意味着墙时间是正确的度量。fork()还有很多工作要做,例如调用atfork函数和清理其他线程的堆栈/TL…@psmears:你说得对。由于glibc的fork与
    sys\u fork
    不完全相同,因此还有很多额外的工作要做。
    #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";
    }
    
    #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";
    
    }
    
    > 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