- 浏览: 403829 次
最新评论
-
iunknown:
909601686 写道我理解下来,之所以使用奇数应该不仅仅是 ...
以两军问题为背景来演绎Basic Paxos -
909601686:
我理解下来,之所以使用奇数应该不仅仅是为了判断谁赢。而是这样就 ...
以两军问题为背景来演绎Basic Paxos -
feclipse:
you are my hero! 看了你的图示之后,我的理解 ...
以两军问题为背景来演绎Basic Paxos -
lcc0739:
相当好!通俗易懂,看了好几篇paxos只有你这个最深入浅出!
以两军问题为背景来演绎Basic Paxos -
iunknown:
tangfu 写道hi,问一下,博主提供的库与pb兼容么,比如 ...
一个轻量的 wire format 解释器(google protobuf 的二进制格式)
SPProcPool 是一个 linux/unix 平台上的进程池服务器框架,使用 c++ 实现。主要包含了几种不同类型的进程池的实现:
一个基于 Leader/Follower 模式的服务器端进程池(类似 apache 的 prefork 模型);
一个组合了 Prefork 和线程池的服务器端框架(类似 apache 的 worker 模型);
一个基于文件句柄传递的服务器端进程池;
一个用于非服务器端的,能够在多线程或事件驱动环境下使用的进程池。
主页:http://code.google.com/p/spprocpool/
下载:spprocpool
关于进程池服务器框架,在《unix网络编程(第二版)》的第 27 章,详细地描述了多种不同的实现方式。
基于 Leader/Follower 模式的实现:27.6 TCP 预先派生子进程服务器程序,accept 无上锁保护
基于文件句柄传递:27.9 TCP 预先派生子进程服务器程序,传递描述字
关于非服务器端的,能够在多线程或事件驱动环境下使用的进程池,这里做一个比较详细的说明。
多线程的好处是各个线程能够共享一个地址空间,因此对一些需要全局排序来调度的任务,使用多线程可以比较方便地实现。比如类似 postfix/qmgr 的模块,如果使用多线程的话,那么所有的邮件能够在一个优先队列中排队,按队列顺序进行投递;如果投递失败了,那么重新插入队列。
但另一方面,如果具体的任务处理部分已经有了实现,但不是线程安全的,这种问题要怎么来解决呢?
一个最直观的解决方法是每个任务直接 fork 一次。但是这种做法有几个细节问题需要认真考虑:
1.在子进程中如何把结果返回给调度进程?常见的方法是使用 pipe
2.每个任务 fork 一次,估计很多人的第一反应就是性能会怎么样?
3.如果调度进程中,除了负责 fork 的线程,还有其他的线程存在,那么就存在 fork-with-thread 的问题。
>>具体的内容可以参考:http://www.opengroup.org/onlinepubs/000095399/functions/fork.html
针对上面存在的问题,在每个任务直接 fork 一次的基础上,做了一些改进,就形成了这样的一个进程池实现:
1.在前面的方案中,存在调度进程(Sched)和工作进程(Worker)这两类进程。
>>为了避免 fork-with-thread 的问题,再增加一类管理进程(Manager)。管理进程的主要职责就是负责 fork 工作进程。
2.通常 Manager 是由 Sched fork 出来的,它们之间存在一条通信的 pipe (MgrPipe) 。
>>创建一个新的工作进程的流程如下:Sched 创建一个 pipe (WorkerPipe),把其中的一端用 send_fd 的方法发送给 Manager,
>>然后 Manager fork 一个 Worker 出来,并且把 WorkerPipe 传递给 Worker 。这样就在 Sched 和 Worker 之间建立了一个 Pipe 。
3.Worker 在被 fork 出来之后,通常就阻塞在读 WorkerPipe 上面。Sched 通过 WorkerPipe 发送任务给 Worker 。
>>Worker 完成任务之后,通过 WorkerPipe 发送结果给 Sched 。Worker 可以不断地重复这个过程,这样就达到了一个池的效果。
4.对于使用 libevent 这类事件驱动类型的程序,这个进程池也能方便地被调用。
>>因为 Worker 曝露出来的是一个 PipeFd,能够方便地加入到 libevent 的事件循环中。这类事件驱动类的程序,
>>通常使用单线程实现,当具体的任务处理可能需要耗费比较长时间的时候,就需要使用多线程或者多进程来辅助了。
SPProcPool 提供了 3 个服务器框架:
SP_ProcInetServer(传递文件句柄)
SP_ProcLFServer(Leader/Follower模型)
SP_ProcMTServer(Worker模型)
它们的定义很类似:
从接口中可以看到,要使用这些框架,需要提供一个 SP_ProcInetServiceFactory 类的实例。这个类相关的定义如下:
这里使用的是典型的抽象工厂方法。在工厂类中,除了 create 方法之外,还有两个特别的方法:workerInit 和 workerEnd 。workerInit 在子进程开始运行的时候被调用,workerEnd 在子进程退出的时候被调用。在 Service 类中,只有一个 handle 方法,它的参数就是已经 accept 到 socket 。
下面以一个简单的服务器为例进行说明。这个服务器是模仿《unix网络编程(第二版)》(中文版)第27章的服务器。服务器从 socket 读入包含一个数字的一行,然后根据这个数字返回相应的内容。
要实现这个简单的服务器例子,代码如下:
不是太明白你说的意思。
是说程序本身已经有大量的 IO ,现在又需要在进程间通信,那么是用 pipe 还是 shm (严格来说,用 shm 的话,还需要一个进程间同步的手段) ? 还是说,这个大量的 IO 就是进程间通信带来的 ?
关于各种进程间通信的手段,在 《UNIX网络编程 第2卷 进程间通信》这本书的附录中,给出了作者的测试结果,也给出了测试程序。针对具体的情况,可以跑一下这些测试程序。
嗯 就是说一个服务器面对的业务是大量IO 但是不需要什么计算
而这个服务器采用了多进程的模式 在这种情况下
父子进程之间需要通信 是shm快还是pipe快
shm是需要同步的
第二卷还没看过
不是太明白你说的意思。
是说程序本身已经有大量的 IO ,现在又需要在进程间通信,那么是用 pipe 还是 shm (严格来说,用 shm 的话,还需要一个进程间同步的手段) ? 还是说,这个大量的 IO 就是进程间通信带来的 ?
关于各种进程间通信的手段,在 《UNIX网络编程 第2卷 进程间通信》这本书的附录中,给出了作者的测试结果,也给出了测试程序。针对具体的情况,可以跑一下这些测试程序。
一个基于 Leader/Follower 模式的服务器端进程池(类似 apache 的 prefork 模型);
一个组合了 Prefork 和线程池的服务器端框架(类似 apache 的 worker 模型);
一个基于文件句柄传递的服务器端进程池;
一个用于非服务器端的,能够在多线程或事件驱动环境下使用的进程池。
主页:http://code.google.com/p/spprocpool/
下载:spprocpool
关于进程池服务器框架,在《unix网络编程(第二版)》的第 27 章,详细地描述了多种不同的实现方式。
基于 Leader/Follower 模式的实现:27.6 TCP 预先派生子进程服务器程序,accept 无上锁保护
基于文件句柄传递:27.9 TCP 预先派生子进程服务器程序,传递描述字
关于非服务器端的,能够在多线程或事件驱动环境下使用的进程池,这里做一个比较详细的说明。
多线程的好处是各个线程能够共享一个地址空间,因此对一些需要全局排序来调度的任务,使用多线程可以比较方便地实现。比如类似 postfix/qmgr 的模块,如果使用多线程的话,那么所有的邮件能够在一个优先队列中排队,按队列顺序进行投递;如果投递失败了,那么重新插入队列。
但另一方面,如果具体的任务处理部分已经有了实现,但不是线程安全的,这种问题要怎么来解决呢?
一个最直观的解决方法是每个任务直接 fork 一次。但是这种做法有几个细节问题需要认真考虑:
1.在子进程中如何把结果返回给调度进程?常见的方法是使用 pipe
2.每个任务 fork 一次,估计很多人的第一反应就是性能会怎么样?
3.如果调度进程中,除了负责 fork 的线程,还有其他的线程存在,那么就存在 fork-with-thread 的问题。
>>具体的内容可以参考:http://www.opengroup.org/onlinepubs/000095399/functions/fork.html
针对上面存在的问题,在每个任务直接 fork 一次的基础上,做了一些改进,就形成了这样的一个进程池实现:
1.在前面的方案中,存在调度进程(Sched)和工作进程(Worker)这两类进程。
>>为了避免 fork-with-thread 的问题,再增加一类管理进程(Manager)。管理进程的主要职责就是负责 fork 工作进程。
2.通常 Manager 是由 Sched fork 出来的,它们之间存在一条通信的 pipe (MgrPipe) 。
>>创建一个新的工作进程的流程如下:Sched 创建一个 pipe (WorkerPipe),把其中的一端用 send_fd 的方法发送给 Manager,
>>然后 Manager fork 一个 Worker 出来,并且把 WorkerPipe 传递给 Worker 。这样就在 Sched 和 Worker 之间建立了一个 Pipe 。
3.Worker 在被 fork 出来之后,通常就阻塞在读 WorkerPipe 上面。Sched 通过 WorkerPipe 发送任务给 Worker 。
>>Worker 完成任务之后,通过 WorkerPipe 发送结果给 Sched 。Worker 可以不断地重复这个过程,这样就达到了一个池的效果。
4.对于使用 libevent 这类事件驱动类型的程序,这个进程池也能方便地被调用。
>>因为 Worker 曝露出来的是一个 PipeFd,能够方便地加入到 libevent 的事件循环中。这类事件驱动类的程序,
>>通常使用单线程实现,当具体的任务处理可能需要耗费比较长时间的时候,就需要使用多线程或者多进程来辅助了。
SPProcPool 提供了 3 个服务器框架:
SP_ProcInetServer(传递文件句柄)
SP_ProcLFServer(Leader/Follower模型)
SP_ProcMTServer(Worker模型)
它们的定义很类似:
class SP_ProcInetServer { public: SP_ProcInetServer( const char * bindIP, int port, SP_ProcInetServiceFactory * factory ); virtual ~SP_ProcInetServer(); virtual int start(); }; class SP_ProcLFServer { public: SP_ProcLFServer( const char * bindIP, int port, SP_ProcInetServiceFactory * factory ); virtual ~SP_ProcLFServer(); virtual int start(); }; class SP_ProcMTServer { public: SP_ProcMTServer( const char * bindIP, int port, SP_ProcInetServiceFactory * factory ); virtual ~SP_ProcMTServer(); virtual int start(); };
从接口中可以看到,要使用这些框架,需要提供一个 SP_ProcInetServiceFactory 类的实例。这个类相关的定义如下:
class SP_ProcInetService { public: virtual ~SP_ProcInetService(); virtual void handle( int socketFd ) = 0; }; class SP_ProcInetServiceFactory { public: virtual ~SP_ProcInetServiceFactory(); virtual SP_ProcInetService * create() const = 0; virtual void workerInit( const SP_ProcInfo * procInfo ); virtual void workerEnd( const SP_ProcInfo * procInfo ); };
这里使用的是典型的抽象工厂方法。在工厂类中,除了 create 方法之外,还有两个特别的方法:workerInit 和 workerEnd 。workerInit 在子进程开始运行的时候被调用,workerEnd 在子进程退出的时候被调用。在 Service 类中,只有一个 handle 方法,它的参数就是已经 accept 到 socket 。
下面以一个简单的服务器为例进行说明。这个服务器是模仿《unix网络编程(第二版)》(中文版)第27章的服务器。服务器从 socket 读入包含一个数字的一行,然后根据这个数字返回相应的内容。
要实现这个简单的服务器例子,代码如下:
class SP_ProcUnpService : public SP_ProcInetService { public: SP_ProcUnpService() {} virtual ~SP_ProcUnpService() {} virtual void handle( int sockfd ) { int ntowrite; ssize_t nread; char line[MAXLINE], result[MAXN]; for ( ; ; ) { if ( (nread = read(sockfd, line, MAXLINE)) == 0) { return; /* connection closed by other end */ } /* line from client specifies #bytes to write back */ ntowrite = atol(line); if ((ntowrite <= 0) || (ntowrite > MAXN)) { syslog( LOG_WARNING, "WARN: client request for %d bytes", ntowrite); exit( -1 ); } SP_ProcPduUtils::writen(sockfd, result, ntowrite); } } }; class SP_ProcUnpServiceFactory : public SP_ProcInetServiceFactory { public: SP_ProcUnpServiceFactory() {} virtual ~SP_ProcUnpServiceFactory() {} virtual SP_ProcInetService * create() const { return new SP_ProcUnpService(); } virtual void workerInit( const SP_ProcInfo * procInfo ) { signal( SIGINT, SIG_DFL ); printf( "pid %d start\n", (int)procInfo->getPid() ); } virtual void workerEnd( const SP_ProcInfo * procInfo ) { printf( "pid %d exit, pipeFd %d, requests %d, lastActiveTime %ld\n", (int)procInfo->getPid(), procInfo->getPipeFd(), procInfo->getRequests(), procInfo->getLastActiveTime() ); } }; int main( int argc, char * argv[] ) { SP_ProcMTServer server( "", 1770, new SP_ProcUnpServiceFactory() ); server.start(); return 0; }
评论
5 楼
ken1984
2008-01-01
直接在内存操作比pipe快,shm也可以是匿名的。
4 楼
seen
2007-12-27
iunknown 写道
seen 写道
多进程服务器,大量IO,少量CPU的情况下,
pipe跟shared memory比起来,效率哪个高?楼主有这方面经验不?
pipe跟shared memory比起来,效率哪个高?楼主有这方面经验不?
不是太明白你说的意思。
是说程序本身已经有大量的 IO ,现在又需要在进程间通信,那么是用 pipe 还是 shm (严格来说,用 shm 的话,还需要一个进程间同步的手段) ? 还是说,这个大量的 IO 就是进程间通信带来的 ?
关于各种进程间通信的手段,在 《UNIX网络编程 第2卷 进程间通信》这本书的附录中,给出了作者的测试结果,也给出了测试程序。针对具体的情况,可以跑一下这些测试程序。
嗯 就是说一个服务器面对的业务是大量IO 但是不需要什么计算
而这个服务器采用了多进程的模式 在这种情况下
父子进程之间需要通信 是shm快还是pipe快
shm是需要同步的
第二卷还没看过
3 楼
iunknown
2007-12-27
seen 写道
多进程服务器,大量IO,少量CPU的情况下,
pipe跟shared memory比起来,效率哪个高?楼主有这方面经验不?
pipe跟shared memory比起来,效率哪个高?楼主有这方面经验不?
不是太明白你说的意思。
是说程序本身已经有大量的 IO ,现在又需要在进程间通信,那么是用 pipe 还是 shm (严格来说,用 shm 的话,还需要一个进程间同步的手段) ? 还是说,这个大量的 IO 就是进程间通信带来的 ?
关于各种进程间通信的手段,在 《UNIX网络编程 第2卷 进程间通信》这本书的附录中,给出了作者的测试结果,也给出了测试程序。针对具体的情况,可以跑一下这些测试程序。
2 楼
seen
2007-12-26
多进程服务器,大量IO,少量CPU的情况下,
pipe跟shared memory比起来,效率哪个高?楼主有这方面经验不?
pipe跟shared memory比起来,效率哪个高?楼主有这方面经验不?
1 楼
iunknown
2007-12-25
对比了传递文件句柄和 Leader/Follower 两种做法的性能,结果是 Leader/Follower 模型比传递文件句柄快。
采用的测试模型就是《Unix网络编程(第二版)》第27章的模型。对书上提到的 client 测试工具做了一下修改,加上了 client 端的时间测量。
测试的时候,两种框架都预先启动 10 个进程,并且 client 端也只跑 10 个进程,每个进程顺序发起 100 个请求,每次请求 512 字节。
针对每种框架,连续运行 client 10 次。每个 client 进程结束的时候,都输出它的总运行时间。最后要对比的就是进程的平均运行时间。
结果:
Leader/Follower 2635 / 100 = 26.35 (毫秒)
Descriptor Passing 3644 / 100 = 36.44 (毫秒)
简单来说,就是在 Leader/Follower 框架下,一个进程处理 100 个请求需要耗时 26 毫秒,而在另外一个框架下,需要 36 毫秒。
采用的测试模型就是《Unix网络编程(第二版)》第27章的模型。对书上提到的 client 测试工具做了一下修改,加上了 client 端的时间测量。
测试的时候,两种框架都预先启动 10 个进程,并且 client 端也只跑 10 个进程,每个进程顺序发起 100 个请求,每次请求 512 字节。
针对每种框架,连续运行 client 10 次。每个 client 进程结束的时候,都输出它的总运行时间。最后要对比的就是进程的平均运行时间。
结果:
Leader/Follower 2635 / 100 = 26.35 (毫秒)
Descriptor Passing 3644 / 100 = 36.44 (毫秒)
简单来说,就是在 Leader/Follower 框架下,一个进程处理 100 个请求需要耗时 26 毫秒,而在另外一个框架下,需要 36 毫秒。
发表评论
-
把开源项目从googlecode转移到github
2015-03-14 23:07 1078前几天看到说 googlecode 准备关闭了,花一个晚上把以 ... -
spcached: memcached 的克隆实现,支持 windows 平台
2009-11-03 22:51 1627memcached 没有官方的 windows 发布版本,只有 ... -
一个轻量的 wire format 解释器(google protobuf 的二进制格式)
2009-10-07 21:38 5023google 的 protobuf 项目,底层的二进制格式设计 ... -
SPHiveDB: 基于 sqlite 的数据库服务器
2009-05-23 23:39 4219在 share nothing 的架构中,如果数据规模很大,为 ... -
spmemvfs: 在内存中加载/保存 sqlite3 数据库
2009-05-01 18:38 3462关于 sqlite3 有很多的介绍文章,这里就不提了。 说一 ... -
SPSmtpGate: SMTP 反垃圾邮件网关
2009-04-16 22:01 1414SPSmtpGate 是一个反垃圾 ... -
SPSmtpServer: 一个基于 SPServer 的 SMTP 服务器框架
2009-03-15 15:08 1502在 SPServer 中增加了一个 smtp 服务器框架。在框 ... -
SPDataPickle: c语言的结构体和 xml/json/protobuf 的自动转化
2009-01-20 00:20 7884SPDataPickle 是一种轻便高效的结构化数据和xml/ ... -
用 state pattern 简化 json 解释器的实现
2008-07-26 11:02 1510之前用 state pattern 实现过 xml 的解释器( ... -
SPNetKit:http/smtp/pop3/memcached 的客户端库
2008-01-13 17:41 3213SPNetKit 主要是一个常见应用层协议的客户端库,使用 C ... -
sptalk:基于 spserver/spxml/spdict 实现的 jabber 服务器
2007-05-25 14:50 3197在 3 年前因为工作需要,搞过一段时间 jabberd 1.4 ... -
spcached : memcached 的多线程实现
2007-05-15 14:43 9852实现 spcached 的目的:不是与 memcached 进 ... -
SPWebServer:一个基于 SPServer 的 web 服务器框架
2007-05-10 16:07 13983看到这个题目,估计很多人会问:为什么要再实现一个 web 服务 ... -
spdict:红黑树(RedBlackTree),平衡树(BalancedTree),SkipList 的实现
2007-04-27 12:11 5362对着 MIT 的 《Introduction to Algor ... -
SPServer : 一个基于线程池(包括HAHS和LF)的高并发 server 框架
2007-03-14 15:13 71980spserver 是一个实现了半同步/半异步(Half-Syn ... -
spxml:使用 state pattern 实现 xml pull/dom parser
2007-01-17 22:26 6099spxml 是一个实现了 pull 和 dom 两种解释模型 ... -
Build a thread pool in C
2006-12-11 16:27 15080想找个轻便的 thread pool ...
相关推荐
某银行的进程池管理代码,,Unix/linux进程池管理
操作系统接口:兼容Unix/Linux命令接口。 为Windows操作系统建立一个兼容Unix命令的命令接口;实现命令包括ls,cat,cp,mv,md/mkdir,rd/rmdir,cd,sort,more,print,命令的内容与详细格式请查阅unix命令手册;可以字符...
这是《Understanding Unix/Linux Programming》书后光盘资源,这本书非常经典,是学习Unix/Linux的好教材,课后资源含有大量的练习。
unix/linux各种命令详解,非常详细
spprocpool 是一个 Unix/Linux 预分叉服务器库。 包括几个 TCP 预分叉的服务器框架。 第一个使用描述符传递,第二个使用Leader/Follower 进程池,第三个使用多处理和多线程模型的组合。 包括一个通用的非服务器进程...
Covering all the essential components of Unix/Linux, including process management, concurrent programming, timer and time service, file systems and network programming, this textbook emphasizes ...
Unix,Linux中sed命令的详解。
实现了进程池的管理, 包括进程池进程数的自动维护,进程退出后会自动重启等。
自己整理的unix/linux信号详解大全,很详细。
《UNIX/Linux系统管理技术手册(第四版)》(ULAHv4)是《Linux系统管理技术手册》和《UNIX系统管理技术手册》的终结版,也是Evi Nemeth的封刀之作。 《UNIX/Linux系统管理技术手册(第四版)》延续了《Linux系统管理...
Unix/Linux 编程实践 附录光盘
介绍loadrunner监控 unix/linux所需要进程, 以及如何启动进程
《Unix\Linux编程实践教程》通过解释Unix的工作原理,循序渐进地讲解实现Unix中系统命令的方法,让读者理解并逐步精通Unix系统编程,进而具有编制Unix应用程序的能力。书中采用启发式、举一反三、图示讲解等多种方法...
为Unix/Linux操作系统建立兼容的Windows/DOS命令接口,文件与目录命令; 具体命令:DIR(my_ls), RD(my_rd),CD,MD(my_md), DEL,MOVE(my_move),REN(my_ren),XCOPY, PROMPT,SORT(sort),TYPE(my_type),COPY(my_copy),...
Unix/Linux基础讲义.doc
建立基于UNIX/LINUX系统网络环境的DNS服务器 一. 实验目标 1.培养Linux 操作系统管理员的DNS网络服务管理技能。 2.系统学习Linux DNS服务器的安装方法。 3.全面掌握Linux DNS服务器的基本配置和测试方法。 二. ...
unix-linux编程实践教程
Unix/Linux/POSIX 通常允许文件名中的几乎任何字节,但这种灵活性是许多问题和漏洞的根源。 此问题在“修复 Unix/Linux/POSIX 文件名:控制字符(例如换行符)、前导破折号和其他问题”...
Unix、Linux平台上的编程实践指南,以C/C++语言为编程语言。