- 浏览: 410039 次
最新评论
-
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 1140前几天看到说 googlecode 准备关闭了,花一个晚上把以 ... -
spcached: memcached 的克隆实现,支持 windows 平台
2009-11-03 22:51 1675memcached 没有官方的 windows 发布版本,只有 ... -
一个轻量的 wire format 解释器(google protobuf 的二进制格式)
2009-10-07 21:38 5102google 的 protobuf 项目,底层的二进制格式设计 ... -
SPHiveDB: 基于 sqlite 的数据库服务器
2009-05-23 23:39 4294在 share nothing 的架构中,如果数据规模很大,为 ... -
spmemvfs: 在内存中加载/保存 sqlite3 数据库
2009-05-01 18:38 3526关于 sqlite3 有很多的介绍文章,这里就不提了。 说一 ... -
SPSmtpGate: SMTP 反垃圾邮件网关
2009-04-16 22:01 1468SPSmtpGate 是一个反垃圾 ... -
SPSmtpServer: 一个基于 SPServer 的 SMTP 服务器框架
2009-03-15 15:08 1567在 SPServer 中增加了一个 smtp 服务器框架。在框 ... -
SPDataPickle: c语言的结构体和 xml/json/protobuf 的自动转化
2009-01-20 00:20 7997SPDataPickle 是一种轻便高效的结构化数据和xml/ ... -
用 state pattern 简化 json 解释器的实现
2008-07-26 11:02 1565之前用 state pattern 实现过 xml 的解释器( ... -
SPNetKit:http/smtp/pop3/memcached 的客户端库
2008-01-13 17:41 3265SPNetKit 主要是一个常见应用层协议的客户端库,使用 C ... -
sptalk:基于 spserver/spxml/spdict 实现的 jabber 服务器
2007-05-25 14:50 3257在 3 年前因为工作需要,搞过一段时间 jabberd 1.4 ... -
spcached : memcached 的多线程实现
2007-05-15 14:43 9915实现 spcached 的目的:不是与 memcached 进 ... -
SPWebServer:一个基于 SPServer 的 web 服务器框架
2007-05-10 16:07 14055看到这个题目,估计很多人会问:为什么要再实现一个 web 服务 ... -
spdict:红黑树(RedBlackTree),平衡树(BalancedTree),SkipList 的实现
2007-04-27 12:11 5424对着 MIT 的 《Introduction to Algor ... -
SPServer : 一个基于线程池(包括HAHS和LF)的高并发 server 框架
2007-03-14 15:13 72190spserver 是一个实现了半同步/半异步(Half-Syn ... -
spxml:使用 state pattern 实现 xml pull/dom parser
2007-01-17 22:26 6167spxml 是一个实现了 pull 和 dom 两种解释模型 ... -
Build a thread pool in C
2006-12-11 16:27 15156想找个轻便的 thread pool ...
相关推荐
在Unix/Linux系统中,进程池(Process Pool)是一种高效的进程管理机制,广泛应用于服务器和后台服务,例如银行系统。进程池的基本思想是预先创建一组进程,这些进程在池中待命,等待处理到来的任务,而不是每次有新...
在Ubuntu VPS上安装Docker时,可能会遇到一个常见的错误:“Cannot connect to the Docker daemon at unix:///var/run/docker.sock.” 这个问题通常是由于Docker守护进程未运行或者是由于Linux内核版本过低导致的。...
书中的内容不仅涵盖了基础的系统调用、文件操作,还包括进程管理、网络编程等高级主题,是学习Unix/Linux系统编程的宝贵资料。光盘资源则为学习过程提供了丰富的实践练习,有助于巩固理论知识,提升实际操作技能。 ...
操作系统接口:兼容Unix/Linux命令接口。 为Windows操作系统建立一个兼容Unix命令的命令接口;实现命令包括ls,cat,cp,mv,md/mkdir,rd/rmdir,cd,sort,more,print,命令的内容与详细格式请查阅unix命令手册;可以字符...
8. **网络编程**:Unix/Linux提供了丰富的网络编程接口,如socket API,可以用来创建TCP/IP或UDP服务,实现客户端-服务器通信。 9. **多线程与并发编程**:线程是并发执行的单元,学习pthread库,理解线程同步...
在Unix/Linux操作系统中,进程池(Process Pool)是一种高效的资源管理策略,用于处理大量并发请求。它通过预先创建一组固定数量的子进程来提供服务,而不是每次请求到来时都创建新的进程,这样可以减少进程创建和...
《Unix/Linux编程实践教程》是一本深入探讨Unix/Linux操作系统编程的实用教材,旨在帮助学习者通过实践提升在这些系统上的编程技能。CD中包含了丰富的学习资源,如PPT课件和编程示例代码,尽管没有提供习题解答,但...
### Unix/Linux sed命令手册知识点详述 #### 一、引言 **Sed** (Stream Editor) 是一种在 Unix 和 Linux 系统中用于文本处理的强大工具。它允许用户通过命令行来自动化文本编辑任务,使得批量编辑文件变得更加简单...
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编程实践教程》是一本深入探讨Unix/Linux操作系统编程的经典教材,涵盖了系统调用、进程管理、文件I/O、网络编程等多个核心领域。习题解答及代码部分是该书的重要补充,它提供了书中各章节练习题的详细...
综上所述,Unix/Linux编程是一项重要的计算机技术基础技能,而《Unix/Linux编程实践教程》是一本被广泛认可的经典教材,它不仅适合作为高等院校的教材使用,也适合自学提升系统编程水平。教材作者的深厚背景和实践...
spprocpool 是一个 Unix/Linux 预分叉服务器库。 包括几个 TCP 预分叉的服务器框架。 第一个使用描述符传递,第二个使用Leader/Follower 进程池,第三个使用多处理和多线程模型的组合。 包括一个通用的非服务器进程...
Unix/Linux 挂载 USB 移动硬盘命令 DVD Unix/Linux 操作系统中,挂载(mount)命令是非常重要的,使用该命令可以将各种外部设备连接到系统中,使用户能够访问这些设备中的数据。下面将详细介绍如何在 Unix/Linux ...
### UNIX/Linux系统管理技术手册(第四版)知识点总结 #### 一、书籍概述 《UNIX/Linux系统管理技术手册(第四版)》(简称ULAHv4)是Evi Nemeth等作者共同编著的一本权威指南,旨在为读者提供全面且深入的UNIX/Linux...
UNIX/Linux系统调用如`fork`用于创建新进程,`exec`系列函数用于执行新的程序,`wait`和`waitpid`用于等待子进程结束。`pthread_create`、`pthread_join`等用于多线程编程。 9. **信号处理**: `signal`函数用于...
《Unix/Linux Shell编程(完整版)权威发布》是一本深入探讨Unix/Linux环境下Shell编程的教程,旨在帮助读者全面掌握Shell脚本的编写技巧和实践应用。对于那些希望提升系统管理效率,或者对自动化任务处理感兴趣的...
Unix/Linux 操作系统中,信号是一种异步事件处理机制,用于通知进程某个事件的发生。信号可以由硬件异常、软件异常、终止进程、进程挂起、定时器到期等事件触发。本文将对 Unix/Linux 信号进行详细的分类和解释。 ...
《理解Unix/Linux编程源代码》是Bruce Molay撰写的一本实战型教程,旨在帮助读者深入理解和掌握Unix/Linux系统下的编程技巧。这本书通过丰富的实例和源代码解析,将复杂的系统编程概念化,使得初学者和有经验的...
在Linux环境中,Docker守护进程通过Unix套接字(unix socket) `/var/run/docker.sock`进行通信。这个套接字允许用户与Docker守护进程交互。当出现“Cannot connect to the Docker daemon”错误时,通常有以下几种可能...