Mar*_*ork 23 c c++ unix multithreading fork
我正在讨论fork()Vs thread()相对于任务并行化的相对成本.
我们了解进程Vs Thread之间的基本区别
线:
流程:
但我们不同意流程Vs线程的启动成本.
因此,为了测试理论,我编写了以下代码.我的问题:这是衡量启动成本的有效测试,还是我遗漏了一些东西.此外,我对每个测试在不同平台上的表现感兴趣.
#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)
#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
咕... ...我不喜欢你的解决方案有很多原因:
您没有考虑子进程/线程的执行时间.
你应该比较cpu-usage而不是经过的时间.这样,您的统计信息将不会依赖于磁盘访问拥塞.
让您的孩子进行一些事情.请记住,"modern"fork使用copy-on-write机制来避免在需要之前为子进程分配内存.立即退出太容易了.这样你就可以避免fork的所有缺点.
CPU时间不是您需要考虑的唯一成本.内存消耗和IPC的缓慢都是fork解决方案的缺点.
您可以使用"rusage"而不是"clock"来衡量实际资源使用情况.
PS我认为你不能真正衡量编写简单测试程序的进程/线程开销.有太多因素,通常,线程和进程之间的选择是由除了cpu使用之外的其他原因驱动的.