草庐IT

c++ - fork() 与 Thread 的公平比较

coder 2023-05-30 原文

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

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

线程:

  • 线程之间易于通信
  • 快速的上下文切换。

进程:

  • 容错。
  • 与 parent 沟通不是真正的问题(打开管道)
  • 难以与其他子进程通信

但我们在进程与线程的启动成本上存在分歧。
因此,为了测试这些理论,我编写了以下代码。我的问题:这是衡量启动成本的有效测试还是我遗漏了什么。此外,我会对每个测试在不同平台上的执行情况感兴趣。

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";
}

线程.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";

}

我希望 Windows 在进程创建方面做得更差。
但我希望现代类 Unix 系统的 fork 成本相当低,并且至少可以与线程相媲美。在较旧的 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

编辑:

做1000个 child 导致fork版本失败。
所以我减少了 child 的数量。但是做一个单一的测试也似乎不公平,所以这里有一个值范围。

最佳答案

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

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

  2. 你应该比较 cpu-usage 而不是实际耗时。这样,您的统计信息就不会依赖于磁盘访问拥塞等因素。

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

  4. CPU 时间并不是您必须考虑的唯一成本。内存消耗和IPC速度慢都是fork方案的缺点。

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

附:我认为您无法真正衡量编写简单测试程序的进程/线程开销。有太多的因素,通常,线程和进程之间的选择是由其他原因驱动的,而不仅仅是 CPU 使用率。

关于c++ - fork() 与 Thread 的公平比较,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3934992/

有关c++ - fork() 与 Thread 的公平比较的更多相关文章

  1. ruby - Ruby 的 Hash 在比较键时使用哪种相等性测试? - 2

    我有一个围绕一些对象的包装类,我想将这些对象用作散列中的键。包装对象和解包装对象应映射到相同的键。一个简单的例子是这样的:classAattr_reader:xdefinitialize(inner)@inner=innerenddefx;@inner.x;enddef==(other)@inner.x==other.xendenda=A.new(o)#oisjustanyobjectthatallowso.xb=A.new(o)h={a=>5}ph[a]#5ph[b]#nil,shouldbe5ph[o]#nil,shouldbe5我试过==、===、eq?并散列所有无济于事。

  2. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  3. ruby - 在 jRuby 中使用 'fork' 生成进程的替代方案? - 2

    在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',

  4. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  5. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  6. ruby - 是否有用于复杂比较的漂亮语法? - 2

    方法应返回-1,0或1分别表示“小于”、“等于”和“大于”。对于某些类型的可排序对象,通常将排序顺序基于多个属性。以下是可行的,但我认为它看起来很笨拙:classLeagueStatsattr_accessor:points,:goal_diffdefinitializepts,gd@points=pts@goal_diff=gdenddefothercompare_pts=pointsother.pointsreturncompare_ptsunlesscompare_pts==0goal_diffother.goal_diffendend尝试一下:[LeagueStats.new(

  7. arrays - Ruby 数组 += vs 推送 - 2

    我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

  8. += 的 Ruby 方法 - 2

    有没有办法让Ruby能够做这样的事情?classPlane@moved=0@x=0defx+=(v)#thisiserror@x+=v@moved+=1enddefto_s"moved#{@moved}times,currentxis#{@x}"endendplane=Plane.newplane.x+=5plane.x+=10putsplane.to_s#moved2times,currentxis15 最佳答案 您不能在Ruby中覆盖复合赋值运算符。任务在内部处理。您应该覆盖+,而不是+=。plane.a+=b与plane.a=

  9. ruby - 尝试比较两个文本文件,并根据信息创建第三个 - 2

    我有两个文本文件,master.txt和926.txt。如果926.txt中有一行不在master.txt中,我想写入一个新文件notinbook.txt。我写了我能想到的最好的东西,但考虑到我是一个糟糕的/新手程序员,它失败了。这是我的东西g=File.new("notinbook.txt","w")File.open("926.txt","r")do|f|while(line=f.gets)x=line.chompifFile.open("master.txt","w")do|h|endwhile(line=h.gets)ifline.chomp!=xputslineendende

  10. ruby - Sinatra + Heroku + Datamapper 使用 dm-sqlite-adapter 部署问题 - 2

    出于某种原因,heroku尝试要求dm-sqlite-adapter,即使它应该在这里使用Postgres。请注意,这发生在我打开任何URL时-而不是在gitpush本身期间。我构建了一个默认的Facebook应用程序。gem文件:source:gemcuttergem"foreman"gem"sinatra"gem"mogli"gem"json"gem"httparty"gem"thin"gem"data_mapper"gem"heroku"group:productiondogem"pg"gem"dm-postgres-adapter"endgroup:development,:t

随机推荐