浅谈并发服务器---对三种并发方式的认识


在上几篇文章中讲了有关服务器的通过多进程,线程,以及I/O复用来实现并发。但我也只是简简单单的使用了以下,但对于具体的进程,线程,I/O复用到底是怎样来实现并发的并不是太清楚,下来就说说对这三种方式的理解。

           高级并发服务器算法流程

(1)统一accept,多进程

  socket(...);

  bind(...);

  listen(...);

  while(1){

  accept(...);

  fork(...);//子进程

 }

 close(...);//关闭服务器套接字

子进程:

 recv(...);

 process(...);

 send(...);

 close(...);//关闭客户端

(2)统一accept,多线程

  socket(...);

  bind(...);

  listen(...);

  while(1){

  accept(...);

  pthread_create(....); 

 }

close(...);//关闭服务器

(3)accept放入每个线程

 socket(...);

 bind(...);

 listen(...);

pthread_create(...);

pthread_join(...);//等待线程结束

close(...);//关闭服务器

线程1:

Mutex_lock//互斥锁

accept(...);

Mutex_unlock(...);

recv(...);

process(...);

send(...);

close(...);//客户端

(4)多路复用

socket(...);

  bind(...);

  listen(...);

  while(1){

    select(......) 或epoll(....)

    {

          accept(......);

    }

  }

对于这三种方式,我想举一个例子来解释。

首先,我们知道,listen(...)函数维护着两个队列,即“未完成链接队列”和"已完成链接队列'.而对于这两个队列是如何操作的呢?下图可以清楚来描述:

 

图的意思就是,当服务器收到客户端发送的建立链接的SYN分节,TCP在未完成队列中创建一个新的条目,然后发送服务器的SYN分节到客户端,并附带对客户SYN的确认ACK。这个条目一直保存在未完成三次握手完毕,该条目将从未完成队列移至已完成队列的队尾。当进程调用accept()函数是,取出已完成链接队列头条目返回给进程,队列为空,进程将睡眠,直到有新的条目到达时才唤醒。

现在,假设有一个宾馆,它是服务器端,而排队进来的入住人就是客户端请求的链接。

第一种,使用fork(),即多进程并发;

        当排着长队要进入宾馆后,前台服务人员将其分为两个队,一个队是还未付钱登记的,另一个队是已付钱登记过的,而发现已付钱登记过得人很多,每次前台服务人员从已付钱登记的队列取一人分配给其他服务人员为客户服务,但发现宾馆的服务人员太少,所以就想要更多的服务人员,但服务器人员从哪来呢?那只能是从社区人力资源市场上招聘得来,但这一过程是相当费时费力,首先要像人力资源市场主管提交申请,然后,主管再填写所要分配的人员的资料等等,最后才将这些人员调给宾馆使用,如此一来,所好费的资源是很大的。

第二种,使用pthread_create(),即多线程并发;

      这种方式与第一种比较相似,不同的地方就是,当宾馆发现服务人员不够时,并不是向人力资源市场上申请了,而是直接调用宾馆中一些后备人员来为当前客户进行服务,相比第一种情况,这种方式更省时省力点。

第三种,将accept放入线程中;

   这种情况就好比,现在有很多等待登记的客户,但是就一个前台服务人员在为客户办理交钱登记业务,效率很慢,而现在,宾馆决定从后勤人员中调出多个人来充当前台服务人员,前台服务人员进行收钱登记并从已付钱登记队列取一人分配给其他服务人员。这样就能加快服务效率。

 第四种, I/0 复用

     与多线程和多进程相比,I/O多路复用的最大优势就是系统开销小,系统不需要建立新的进程或线程,也不必维护这些线程或进程。

     在I/O复用中可以用到select /poll和epoll, 其实select和poll有相同的功能,性能上的差异也不是很大,而epoll 的使用效率会更高,现在来说前两种和epoll的区别,例如,前两种就像,现在宾馆来了很多的客户,门口的迎宾员首先为这些客户排队登记,之后前台服务员就从迎宾员那拷贝他所登记的客户序号,名字等信息并等待客户来交钱登记,但有些客户的证件和钱没带够(这里就相当是服务器的读写,异常状态是否准备好),那就没法给他办理登记了,但有些客户却带好了,所以前台服务人员就前去一个人一个人的去询问他们是否带够了证件和钱,如果带够了就为其登记服务并叫其他服务员为客户服务。之后像这样,前台服务人员先从迎宾员那拷贝客户信息,然后再去询问客户是否到准备好证件和钱,这样的效率不会很高。而epoll()和其相比,确有很大的改善,现在前台服务人员一个一个去讯问太慢了,于是,他想出一个办法,就是开始的时候就把客户的信息从迎宾员那拷贝过来并保存起来,以后就不再去拷贝了,除非有新的客人进来,然后告诉客户,你们中有谁准备好了就排成一队,前台服务人员休息完后就看这准备好证件的队列有人没,如果有就为其登记并安排其他服务人员为你服务,没有就接着休息。

有时候这几种方法并不是独立存在的,他们也是可以同时使用的,多进程+I/O复用+多线程。


这一片文章讲的不错:点击打开链接



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值