C++ fork()与Thread的公平比较
我在讨论fork()与thread()在任务并行化方面的相对成本 我们理解进程与线程之间的基本区别 线程:C++ fork()与Thread的公平比较,c++,c,multithreading,unix,fork,C++,C,Multithreading,Unix,Fork,我在讨论fork()与thread()在任务并行化方面的相对成本 我们理解进程与线程之间的基本区别 线程: 易于在线程之间通信 快速上下文切换 过程: 容错性 与家长沟通不是真正的问题(打开管道) 与其他子进程的通信困难 但我们在进程与线程的启动成本方面存在分歧。 为了测试这些理论,我编写了以下代码。我的问题是:这是衡量启动成本的有效测试,还是我遗漏了什么。此外,我还对每个测试在不同平台上的执行方式感兴趣 fork.cpp 编辑: 执行1000个子项的操作导致fork版本失败。 所以我减
- 易于在线程之间通信
- 快速上下文切换
- 容错性
- 与家长沟通不是真正的问题(打开管道)
- 与其他子进程的通信困难
为了测试这些理论,我编写了以下代码。我的问题是:这是衡量启动成本的有效测试,还是我遗漏了什么。此外,我还对每个测试在不同平台上的执行方式感兴趣 fork.cpp 编辑: 执行1000个子项的操作导致fork版本失败。
所以我减少了孩子的数量。但是做一个单独的测试似乎也不公平,所以这里有一个值范围。在Linux下
fork
是对sys\u clone
的一个特殊调用,无论是在库中还是在内核中。Clone有很多开关可以打开和关闭,每个开关都会影响启动的成本
实际的库函数
clone
可能比fork
更昂贵,因为它做的更多,尽管大部分都在子端(堆栈交换和通过指针调用函数)。咕哝。。。我不喜欢您的解决方案,原因有很多:
另外,我认为编写一个简单的测试程序并不能真正衡量进程/线程开销。有太多的因素,通常情况下,线程和进程之间的选择是由其他原因驱动的,而不仅仅是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