逐步实现TCP服务端Step04:应对多客户

先考虑一下现实生活中,“服务方”是如何为多个客户提供服务的。以去菜市场买菜为例说明,卖菜的商家为服务提供方。

常见的情形是数个客户站在摊位前与商家进行交易,一次完整的交易通常有三个步骤:客户向商家询价(下单),商家交货,客户付款。

这里不必纠结于客户的组织形式,是排队还是怎么样,这不在商家的业务范围内。客户可以自发地使用某种可体现公平原则的机制,比如先到先服务的排队机制。

要满足这些客户的服务要求,商家可以有以下几种方案:

方案一:简单地逐个服务。就是选一个客户完成询价,交货,付款操作,然后再选下一个客户,以此类推。


这是一种顺序的处理方式,其问题是排在后面的客户总是要做一些无谓的等待。等待的时长取决于前面那个客户服务持续的时间。

仔细想想,这个服务时间,其实是有“水分”的。举例说,在客户要付款的时候,通常有一个拿钱包再从钱包里找钱的动作,而这个时候,商家其实是“闲置”的,他什么都没干,就是等着客户付钱。

要减少客户的等待时间,商家必须充分利用时间,时刻处于忙碌状态,不能阻塞在类似于客户找钱这件事情上。

方案二:不要阻塞,充分利用时间。在方案一的基础上稍加改进,商家在为当前客户提供服务的时候,一旦发现此客户有未准备就绪的情况出现,就立即转向那些已准备好了的客户,继续为他们服务。


这种做法消除了阻塞,把商家的闲暇时间都利用了起来。例如,当A还在找钱的时候,商家可以去响应B的询价,然后为C取菜打包,此时C的钱如果还未准备好的话,可以先去收A的钱。

方案三:使用多个服务人员提供服务。方案二剔除了等待时间中的“闲置”时间,实际上,导致客户长时间等待的还有一些“正事”。询价,交货,付款就是商家要做的正事,其中交货(包括取菜,称重,打包,最后交给客户)这个环节费的时间就会多一些。而且,在这个过程中,通常是不便于处理其他客户的请求的,比如用几秒就能搞定的询价请求。时间已经充分利用,此时的商家处于“忙不过来”的状态,只能增加人手予以缓解。

极端的情况是为每个客户分配一个服务员(并行处理)。这样的话,当服务员闲置的时候,就不用考虑为其它客户服务的问题了,因为每个客户都有自己的服务员。不过,这种情况不太可能出现,很显然,对商家来说,成本太高。而且,这么做实际上商家的服务能力是过剩的,让一个人只专注于服务单个客户,这个人就会比较闲,这些闲置的时间就被白白浪费了。

方案四:分工。第三个方案之所以要增加人手,是因为交货是一件比较耗时的事情。同时,在做此事时,该服务员不方便去响应其他客户。增加人手,可以维持对其他客户的响应。不过,仔细想一下,不论增加多少服务员,每个人都是要做交货这件事的。假设一共有4个服务员,碰巧都在做交货这件事,若此时共有20个客户,那就意味着有16个人的请求将在一段时间内没人响应。应安排一个人专门去受理那些除交货之外的耗时很短的请求。

在询价,交货,付款这三件事中,耗时较少的是询价和付款。安排一个人去包办这两件事,至于交货,可以安排一个或多个人去做。负责询价、付款的那个服务员是直接与客户打交道的,而负责交货的人只与这个服务员对接,根据他提供的信息,来取指定重量的指定蔬菜。

第一个方案对应于带阻塞的单线程模型,第二个是非阻塞的单线程模型,第三和第四个都是多线程或多进程模型,不同的是方案四中的进程或线程按照工作内容分成了两类。

就我们所实现的后台程序的形式来看,属于第四个方案。前置的netio进程负责与client打交道,负责所有网络I/O任务,后面的s进程则处理实际业务。

此后仍将继续沿用目前的这个模型去研究多客户的并发处理,对于其它模型暂时不做讨论。



<==  index  ==>