half-sync/half-async 和 Leader/Followers 模式的主要区别

2024-02-12 12:32

本文主要是介绍half-sync/half-async 和 Leader/Followers 模式的主要区别,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在 《POSA2》 一书中,关于这两个模式有两个很形象的比喻:

半同步/半异步(half-sync/half-async):
许多餐厅使用 半同步/半异步 模式的变体。例如,餐厅常常雇佣一个领班负责迎接顾客,并在餐厅繁忙时留意给顾客安排桌位,为等待就餐的顾客按序排队是必要的。领班由所有顾客“共享”,不能被任何特定顾客占用太多时间。当顾客在一张桌子入坐后,有一个侍应生专门为这张桌子服务。

领导者/追随者(Leader/Followers):
在日常生活中,领导者/追随者模式用于管理许多飞机场出租车候车台。在该用例中,出租车扮演“线程”角色,排在第一辆的出租车成为 领导者,剩下的出租车成为 追随者。同样,到达出租车候车台的乘客构成了必须被多路分解给出租车的事件,一般以先进先出排序。一般来说,如果任何出租车可以为任何顾客服务,该场景就主要相当于 非绑定句柄/线程关联。然而,如果仅仅是某些出租车可以为某些乘客服务,该场景就相当于 绑定句柄/线程关联。

在 《POSA2》 书中列举的例子都比较复杂,并且书上没有列出完整的代码。但是这两个模式其实都可以在 《unix网络编程》一书中找到对应的完整的代码和相关的讨论。

在 半同步/半异步 模式中,需要由模式实现者显示构造一个队列,以便同步层和异步层可以通信。
在 《unix网络编程》 一书的 “27.12 TCP预先创建线程服务器程序,主线程统一 accept” 的例子中, 如果只是从处理 accept 这个事件上看,可以认为这是一个使用了 半同步/半异步 模式的例子。但是从具体的业务处理(即web_child的处理上),仍然可以认为是一个ThreadPerConnection模型,因为在 thread_main 中直接读取请求和发送响应。在这个例子中,就有一个队列:

Java代码   收藏代码
  1. [b]//这就是一个典型的循环队列的定义,iget 是队列头,iput 是队列尾[/b]  
  2. int clifd[MAXNCLI], iget, iput;   
  3.   
  4. int main( int argc, char * argv[] )  
  5. {  
  6.   ......  
  7.   int listenfd = Tcp_listen( NULL, argv[ 1 ], &addrlen );  
  8.   ......  
  9.   
  10.   iget = iput = 0;  
  11.   
  12.   forint i = 0; i < nthreads; i++ ) {  
  13.     pthread_create( &tptr[i].thread_tid, NULL, &thread_main, (void*)i );  
  14.   
  15.   for( ; ; ) {  
  16.     connfd = accept( listenfd, cliaddr,, &clilen );  
  17.     clifd[ iput ] = connfd;     [b]// 接受到的连接句柄放入队列[/b]  
  18.     if( ++iput == MAXNCLI ) iput = 0;    
  19.   }  
  20. }  
  21.   
  22. void * thread_main( void * arg )  
  23. {  
  24.   for( ; ; ) {  
  25.     while( iget == iput ) pthread_cond_wait( ...... );  
  26.     connfd = clifd[ iget ];     [b]// 从队列中获得连接句柄[/b]  
  27.     if( ++iget == MAXNCLI ) iget = 0;  
  28.     ......  
  29.     web_child( connfd );  
  30.     close( connfd );  
  31.   }  
  32. }  



而在 领导者/追随者 模式中,同样是有一个队列的,不过不需要模式实现者显示构造,而是直接使用了操作系统底层的队列。

在 《unix网络编程》 一书的 “27.11 TCP 预先创建服务器线程,每个线程各自 accept ” 的例子中,就是直接使用了操作系统中关于 accept 的队列。这个例子可以认为是 领导者/追随者 模式的一个例子。

Java代码   收藏代码
  1. int listenfd;  
  2.   
  3. int main( int argc, char * argv[] )  
  4. {  
  5.   ......  
  6.   listenfd = Tcp_listen( NULL, argv[ 1 ], &addrlen );  
  7.   ......  
  8.   forint i = 0; i < nthreads; i++ ){  
  9.     pthread_create( &tptr[i].thread_tid, NULL, &thread_main, (void*)i );  
  10.   }  
  11.   ......  
  12. }  
  13.   
  14. void * thread_main( void * arg )  
  15. {  
  16.   for( ; ; ){  
  17.     ......  
  18.     [b]// 多个线程同时阻塞在这个 accept 调用上,依靠操作系统的队列[/b]  
  19.     connfd = accept( listenfd, cliaddr, &clilen );  
  20.     ......  
  21.     web_child( connfd );  
  22.     close( connfd );  
  23.     ......  
  24.   }  
  25. }  


当然,这里提到的操作系统的队列,在 半同步/半异步 模式中虽然没有明显地指出来,但只要是通过操作系统来做 accept ,那么在 半同步/半异步 模式中仍然会隐式地用到。

在 《POSA2》中,作者的评价:
因为半同步/半异步设计在 web 服务器虚拟内存而不是操作系统内核内排队请求,所以它更具伸缩性。


看了上面的代码之后,明白了为何 ACE 的作者在 《C++网络编程2》 中特意引用了一首诗来“表达我们对 Richard 之持久影响的看法”:

不是在悲哀的冥河之滨,也不是在遥远的
乐土般的平原的清辉中,我们将在死者中间
遇见那些我们一直是其学生的人 ... ...
我们还将相遇,分离,再相遇,
在死者们相遇的地方,在活着的人的唇上


关于不同的客户-服务器编程模型,在 《unix网络编程》的 “第27章 客户-服务器程序的其他设计方法”中讨论得很充分,对每种模型的性能也做了很好的分析。

这篇关于half-sync/half-async 和 Leader/Followers 模式的主要区别的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/702597

相关文章

MyBatis中$与#的区别解析

《MyBatis中$与#的区别解析》文章浏览阅读314次,点赞4次,收藏6次。MyBatis使用#{}作为参数占位符时,会创建预处理语句(PreparedStatement),并将参数值作为预处理语句... 目录一、介绍二、sql注入风险实例一、介绍#(井号):MyBATis使用#{}作为参数占位符时,会

Android kotlin中 Channel 和 Flow 的区别和选择使用场景分析

《Androidkotlin中Channel和Flow的区别和选择使用场景分析》Kotlin协程中,Flow是冷数据流,按需触发,适合响应式数据处理;Channel是热数据流,持续发送,支持... 目录一、基本概念界定FlowChannel二、核心特性对比数据生产触发条件生产与消费的关系背压处理机制生命周期

Javaee多线程之进程和线程之间的区别和联系(最新整理)

《Javaee多线程之进程和线程之间的区别和联系(最新整理)》进程是资源分配单位,线程是调度执行单位,共享资源更高效,创建线程五种方式:继承Thread、Runnable接口、匿名类、lambda,r... 目录进程和线程进程线程进程和线程的区别创建线程的五种写法继承Thread,重写run实现Runnab

C++中NULL与nullptr的区别小结

《C++中NULL与nullptr的区别小结》本文介绍了C++编程中NULL与nullptr的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编... 目录C++98空值——NULLC++11空值——nullptr区别对比示例 C++98空值——NUL

Conda与Python venv虚拟环境的区别与使用方法详解

《Conda与Pythonvenv虚拟环境的区别与使用方法详解》随着Python社区的成长,虚拟环境的概念和技术也在不断发展,:本文主要介绍Conda与Pythonvenv虚拟环境的区别与使用... 目录前言一、Conda 与 python venv 的核心区别1. Conda 的特点2. Python v

Go语言中make和new的区别及说明

《Go语言中make和new的区别及说明》:本文主要介绍Go语言中make和new的区别及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1 概述2 new 函数2.1 功能2.2 语法2.3 初始化案例3 make 函数3.1 功能3.2 语法3.3 初始化

Java设计模式---迭代器模式(Iterator)解读

《Java设计模式---迭代器模式(Iterator)解读》:本文主要介绍Java设计模式---迭代器模式(Iterator),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录1、迭代器(Iterator)1.1、结构1.2、常用方法1.3、本质1、解耦集合与遍历逻辑2、统一

Java 线程安全与 volatile与单例模式问题及解决方案

《Java线程安全与volatile与单例模式问题及解决方案》文章主要讲解线程安全问题的五个成因(调度随机、变量修改、非原子操作、内存可见性、指令重排序)及解决方案,强调使用volatile关键字... 目录什么是线程安全线程安全问题的产生与解决方案线程的调度是随机的多个线程对同一个变量进行修改线程的修改操

深度解析Spring Boot拦截器Interceptor与过滤器Filter的区别与实战指南

《深度解析SpringBoot拦截器Interceptor与过滤器Filter的区别与实战指南》本文深度解析SpringBoot中拦截器与过滤器的区别,涵盖执行顺序、依赖关系、异常处理等核心差异,并... 目录Spring Boot拦截器(Interceptor)与过滤器(Filter)深度解析:区别、实现

Before和BeforeClass的区别及说明

《Before和BeforeClass的区别及说明》:本文主要介绍Before和BeforeClass的区别及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Before和BeforeClass的区别一个简单的例子当运行这个测试类时总结Before和Befor