精华内容
下载资源
问答
  • 11 | 并发模式:Go 语言中即学即用的高效并发模式 如何通过 Context 实现日志跟踪? 要想跟踪一个用户的请求,必须有一个唯一的 ID 来标识这次请求调用了哪些函数、执行了哪些代码,然后通过这个唯一的 ID 把日志...

    11 | 并发模式:Go 语言中即学即用的高效并发模式

    如何通过 Context 实现日志跟踪?

    要想跟踪一个用户的请求,必须有一个唯一的 ID 来标识这次请求调用了哪些函数、执行了哪些代码,然后通过这个唯一的 ID 把日志信息串联起来。这样就形成了一个日志轨迹,也就实现了用户的跟踪,于是思路就有了。

    1. 在用户请求的入口点生成 TraceID。

    2. 通过 context.WithValue 保存 TraceID。

    3. 然后这个保存着 TraceID 的 Context 就可以作为参数在各个协程或者函数间传递。

    4. 在需要记录日志的地方,通过 Context 的 Value 方法获取保存的 TraceID,然后把它和其他日志信息记录下来。

    5. 这样具备同样 TraceID 的日志就可以被串联起来,达到日志跟踪的目的。

    以上思路实现的核心是 Context 的传值功能。

    目前我们已熟练掌握了 goroutine、channel、sync 包的同步原语,这些都是并发编程比较基础的元素。而这节课要介绍的是如何用这些基础元素组成并发模式,帮助我们更好地编写并发程序。

    for select 循环模式

    for select 循环模式非常常见,在前面也使用过,它一般和 channel 组合完成任务,代码格式如下:

    for { //for无限循环,或者for range循环
      select {
        //通过一个channel控制
      }
    }
    

    这是一种 for 循环 +select 多路复用的并发模式,哪个 case 满足就执行哪个,直到满足一定的条件退出 for 循环(比如发送退出信号)。

    从具体实现上讲,for select 循环有两种模式,一种是上面监控狗例子中的无限循环模式,只有收到终止指令才会退出,如下所示:

    for  {
       select {
       case <-done:
          return
       default:
          //执行具体的任务
       }
     }
    

    这种模式会一直执行 default 语句中的任务,直到 done 这个 channel 被关闭为止。

    第二种模式是 for range select 有限循环,一般用于把可以迭代的内容发送到 channel 上,如下所示:

    for _,s:=range []int{}{
       select {
       case <-done:
          return
       case resultCh <- s:
       }
    }
    

    这种模式也会有一个 done channel,用于退出当前的 for 循环,而另外一个 resultCh channel 用于接收 for range 循环的值,这些值通过 resultCh 可以传送给其他的调用者。

    select timeout 模式

    假如需要访问服务器获取数据,因为网络的不同响应时间不一样,为保证程序的质量,不可能一直等待网络返回,所以需要设置一个超时时间,这时候就可以使用 select timeout 模式,如下所示:

    func main() {
       result := make(chan string)
       go func() {
          //模拟网络访问
          time.Sleep(8 * time.Second)
          result <- "服务端结果"
       }()
       select {
       case v := <-result:
          fmt.Println(v)
       case <-time.After(5 * time.Second):
          fmt.Println("网络访问超时了")
       }
    }
    

    select timeout 模式的核心在于通过 time.After 函数设置一个超时时间,防止因为异常造成 select 语句的无限等待。

    小提示:如果可以使用 Context 的 WithTimeout 函数超时取消,要优先使用。

    Pipeline 模式

    Pipeline 模式也称为流水线模式,模拟的就是现实世界中的流水线生产。以手机组装为例,整条生产流水线可能有成百上千道工序,每道工序只负责自己的事情,最终经过一道道工序组装,就完成了一部手机的生产。

    从技术上看,每一道工序的输出,就是下一道工序的输入,在工序之间传递的东西就是数据,这种模式称为流水线模式,而传递的数据称为数据流。
    图片1.png
    (流水线模式)

    通过以上流水线模式示意图,可以看到从最开始的生产,经过工序 1、2、3、4 到最终成品,这就是一条比较形象的流水线,也就是 Pipeline。

    现在我以组装手机为例,讲解流水线模式的使用。假设一条组装手机的流水线有 3 道工序,分别是配件采购、配件组装、打包成品,如图所示:
    图片2.png
    (手机组装流水线)

    从以上示意图中可以看到,采购的配件通过 channel 传递给工序 2 进行组装,然后再通过 channel 传递给工序 3 打包成品。相对工序 2 来说,工序 1 是生产者,工序 3 是消费者。相对工序 1 来说,工序 2 是消费者。相对工序 3 来说,工序 2 是生产者。

    我用下面的几组代码进行演示:

    //工序1采购
    func buy(n int) <-chan string {
       out := make(chan string)
       go func() {
          defer close(out)
          for i := 1; i <= n; i++ {
             out <- fmt.Sprint("配件", i)
          }
       }()
       return out
    }
    

    首先我们定义一个采购函数 buy,它有一个参数 n,可以设置要采购多少套配件。采购代码的实现逻辑是通过 for 循环产生配件,然后放到 channel 类型的变量 out 里,最后返回这个 out,调用者就可以从 out 中获得配件。

    有了采购好的配件,就可以开始组装了,如下面的代码所示:

    //工序2组装
    func build(in <-chan string) <-chan string {
       out := make(chan string)
       go func() {
          defer close(out)
          for c := range in {
             out <- "组装(" + c + ")"
          }
       }()
       return out
    }
    

    组装函数 build 有一个 channel 类型的参数 in,用于接收配件进行组装,组装后的手机放到 channel 类型的变量 out 中返回。

    有了组装好的手机,就可以放在精美的包装盒中售卖了,而包装的操作是工序 3 完成的,对应的函数是 pack,如下所示:

    //工序3打包
    func pack(in <-chan string) <-chan string {
       out := make(chan string)
       go func() {
          defer close(out)
          for c := range in {
             out <- "打包(" + c + ")"
          }
       }()
       return out
    }
    

    函数 pack 的代码实现和组装函数 build 基本相同,这里不再赘述。

    流水线上的三道工序都完成后,就可以通过一个组织者把三道工序组织在一起,形成一条完整的手机组装流水线,这个组织者可以是我们常用的 main 函数,如下面的代码所示:

    func main() {
       coms := buy(10)    //采购10套配件
       phones := build(coms) //组装10部手机
       packs := pack(phones) //打包它们以便售卖
       //输出测试,看看效果
       for p := range packs {
          fmt.Println(p)
       }
    }
    

    按照流水线工序进行调用,最终把手机打包以便售卖,过程如下所示:

    打包(组装(配件1))
    打包(组装(配件2))
    打包(组装(配件3))
    打包(组装(配件4))
    打包(组装(配件5))
    打包(组装(配件6))
    打包(组装(配件7))
    打包(组装(配件8))
    打包(组装(配件9))
    打包(组装(配件10))
    

    从上述例子中,我们可以总结出一个流水线模式的构成:

    流水线由一道道工序构成,每道工序通过 channel 把数据传递到下一个工序;

    每道工序一般会对应一个函数,函数里有协程和 channel,协程一般用于处理数据并把它放入 channel 中,整个函数会返回这个 channel 以供下一道工序使用;

    最终要有一个组织者(示例中的 main 函数)把这些工序串起来,这样就形成了一个完整的流水线,对于数据来说就是数据流。

    扇出和扇入模式
    手机流水线经过一段时间的运转,组织者发现产能提不上去,经过调研分析,发现瓶颈在工序 2 配件组装。工序 2 过慢,导致上游工序 1 配件采购速度不得不降下来,下游工序 3 没太多事情做,不得不闲下来,这就是整条流水线产能低下的原因。

    为了提升手机产能,组织者决定对工序 2 增加两班人手。人手增加后,整条流水线的示意图如下所示:
    图片3.png
    (改进后的流水线)

    从改造后的流水线示意图可以看到,工序 2 共有工序 2-1、工序 2-2、工序 2-3 三班人手,工序 1 采购的配件会被工序 2 的三班人手同时组装,这三班人手组装好的手机会同时传给merge 组件汇聚,然后再传给工序 3 打包成品。在这个流程中,会产生两种模式:扇出和扇入。

    示意图中红色的部分是扇出,对于工序 1 来说,它同时为工序 2 的三班人手传递数据(采购配件)。以工序 1 为中点,三条传递数据的线发散出去,就像一把打开的扇子一样,所以叫扇出。

    示意图中蓝色的部分是扇入,对于 merge 组件来说,它同时接收工序 2 三班人手传递的数据(组装的手机)进行汇聚,然后传给工序 3。以 merge 组件为中点,三条传递数据的线汇聚到 merge 组件,也像一把打开的扇子一样,所以叫扇入。

    小提示:扇出和扇入都像一把打开的扇子,因为数据传递的方向不同,所以叫法也不一样,扇出的数据流向是发散传递出去,是输出流;扇入的数据流向是汇聚进来,是输入流。

    已经理解了扇出扇入的原理,就可以开始改造流水线了。这次改造中,三道工序的实现函数 buy、build、pack 都保持不变,只需要增加一个 merge 函数即可,如下面的代码所示:

    //扇入函数(组件),把多个chanel中的数据发送到一个channel中
    func merge(ins ...<-chan string) <-chan string {
       var wg sync.WaitGroup
       out := make(chan string)
       //把一个channel中的数据发送到out中
       p:=func(in <-chan string) {
          defer wg.Done()
          for c := range in {
             out <- c
          }
       }
       wg.Add(len(ins))
       //扇入,需要启动多个goroutine用于处于多个channel中的数据
       for _,cs:=range ins{
          go p(cs)
       }
       //等待所有输入的数据ins处理完,再关闭输出out
       go func() {
          wg.Wait()
          close(out)
       }()
       return out
    }
    

    新增的 merge 函数的核心逻辑就是对输入的每个 channel 使用单独的协程处理,并将每个协程处理的结果都发送到变量 out 中,达到扇入的目的。总结起来就是通过多个协程并发,把多个 channel 合成一个。

    在整条手机组装流水线中,merge 函数非常小,而且和业务无关,不能当作一道工序,所以我把它叫作组件。该 merge 组件是可以复用的,流水线中的任何工序需要扇入的时候,都可以使用 merge 组件。

    小提示:这次的改造新增了 merge 函数,其他函数保持不变,符合开闭原则。开闭原则规定“软件中的对象(类,模块,函数等等)应该对于扩展是开放的,但是对于修改是封闭的”。

    有了可以复用的 merge 组件,现在来看流水线的组织者 main 函数是如何使用扇出和扇入并发模式的,如下所示:

    func main() {
       coms := buy(100)    //采购100套配件
       //三班人同时组装100部手机
       phones1 := build(coms)
       phones2 := build(coms)
       phones3 := build(coms)
       //汇聚三个channel成一个
       phones := merge(phones1,phones2,phones3)
       packs := pack(phones) //打包它们以便售卖
       //输出测试,看看效果
       for p := range packs {
          fmt.Println(p)
       }
    }
    

    这个示例采购了 100 套配件,也就是开始增加产能了。于是同时调用三次 build 函数,也就是为工序 2 增加人手,这里是三班人手同时组装配件,然后通过 merge 函数这个可复用的组件将三个 channel 汇聚为一个,然后传给 pack 函数打包。

    这样通过扇出和扇入模式,整条流水线就被扩充好了,大大提升了生产效率。因为已经有了通用的扇入组件 merge,所以整条流水中任何需要扇出、扇入提高性能的工序,都可以复用 merge 组件做扇入,并且不用做任何修改。

    Futures 模式

    Pipeline 流水线模式中的工序是相互依赖的,上一道工序做完,下一道工序才能开始。但是在我们的实际需求中,也有大量的任务之间相互独立、没有依赖,所以为了提高性能,这些独立的任务就可以并发执行。

    举个例子,比如我打算自己做顿火锅吃,那么就需要洗菜、烧水。洗菜、烧水这两个步骤相互之间没有依赖关系,是独立的,那么就可以同时做,但是最后做火锅这个步骤就需要洗好菜、烧好水之后才能进行。这个做火锅的场景就适用 Futures 模式。

    Futures 模式可以理解为未来模式,主协程不用等待子协程返回的结果,可以先去做其他事情,等未来需要子协程结果的时候再来取,如果子协程还没有返回结果,就一直等待。我用下面的代码进行演示:

    //洗菜
    func washVegetables() <-chan string {
       vegetables := make(chan string)
       go func() {
          time.Sleep(5 * time.Second)
          vegetables <- "洗好的菜"
       }()
       return vegetables
    }
    //烧水
    func boilWater() <-chan string {
       water := make(chan string)
       go func() {
          time.Sleep(5 * time.Second)
          water <- "烧开的水"
       }()
       return water
    }
    

    洗菜和烧水这两个相互独立的任务可以一起做,所以示例中通过开启协程的方式,实现同时做的功能。当任务完成后,结果会通过 channel 返回。

    小提示:示例中的等待 5 秒用来描述洗菜和烧火的耗时。

    在启动两个子协程同时去洗菜和烧水的时候,主协程就可以去干点其他事情(示例中是眯一会),等睡醒了,要做火锅的时候,就需要洗好的菜和烧好的水这两个结果了。我用下面的代码进行演示:

    func main() {
       vegetablesCh := washVegetables() //洗菜
       waterCh := boilWater()           //烧水
       fmt.Println("已经安排洗菜和烧水了,我先眯一会")
       time.Sleep(2 * time.Second)
    
       fmt.Println("要做火锅了,看看菜和水好了吗")
       vegetables := <-vegetablesCh
       water := <-waterCh
       fmt.Println("准备好了,可以做火锅了:",vegetables,water)
    }
    

    Futures 模式下的协程和普通协程最大的区别是可以返回结果,而这个结果会在未来的某个时间点使用。所以在未来获取这个结果的操作必须是一个阻塞的操作,要一直等到获取结果为止。

    如果你的大任务可以拆解为一个个独立并发执行的小任务,并且可以通过这些小任务的结果得出最终大任务的结果,就可以使用 Futures 模式。

    总结

    并发模式和设计模式很相似,都是对现实场景的抽象封装,以便提供一个统一的解决方案。但和设计模式不同的是,并发模式更专注于异步和并发。

    展开全文
  • 一、基本概念 半同步/半异步模式中的“同步”...而在并发模式下,“同步”指程序完全按照代码顺序执行;“异步”指程序的执行需要系统事件来驱动。 显然异步线程的执行效率能高一点,实时性强,但是他适用于大量...

    一、基本概念

    半同步/半异步模式中的“同步”和“异步”与“I/O模式”下的同步与异步是有区别的,在I/O模式下,同步与异步区分的是内核向应用程序通知的是何种I/O时间(是就绪事件还是完成时间),以及谁来完成I/O读写(是应用程序还是内核)。而在并发模式下,“同步”指程序完全按照代码顺序执行;“异步”指程序的执行需要系统事件来驱动。

    显然异步线程的执行效率能高一点,实时性强,但是他适用于大量并发操作,因为其程序复杂,难以调试和扩展。

    对于向服务器这种既要求实时性高,又能同时处理多个客户请求的应用程序。我们就应该同时使用同步和异步两种模型来实现,即半同步/半异步模型。

    首先给出服务器程序的基本框架

    在半同步/半异步模型中,同步线程用于处理客户逻辑,相当于框架中的逻辑单元,而异步线程用于处理I/O事件,相当于框架中的I/O处理单元。异步线程监听到客户请求之后,就将其封装成请求对象,插入到请求队列,请求队列将会通知某个工作在同步线程中的工作线程来读取并请求对象。

    二、工作流程图

    三、半同步/半反应堆模式

    在服务器程序中,如果考虑到事件处理模式和几种I/O模型的话,半同步/半异步模式就会有许多变体。其中一种变体就叫做半同步/半反应堆模式。

      在这种模式下,异步线程只有一个,由主线程来充当。主要负责监听socket上的事件。如果监听到socket上有可读事件发生,即有新的请求事件到来,主线程就接受之,并连接新的连接socket,然后往内核事件表中注册socket上的读写事件。如果连接上的socket有读写事件发生,即有新的客户请求到来,或者有数据要发送到客户端,主线程就该连接socket插入到请求队列,所有工作线程睡眠在请求队列当中,当任务到来的时候,他们将通过竞争,获得任务的接管权。

      主线程插入请求队列中的任务就是就是就绪连接的socket,说明半同步/半反应堆采用的事件处理方是Reactor模式:他要求工作线程自己从socket上读取客户请求和往socket写入服务器应答。

    半同步/半反应堆模式存在以下缺点:

    • 主线程和工作队列共享请求队列,主线程往请求队列中添加任务,工作线程从请求队列中取出任务,都需要进行对请求队列进行加锁保护,从而白白浪费了CPU时间。
    • 每个工作线程在同一时间内只能处理一个客户的请求。如果客户数量较多,而工作线程较少,那么请求队列将会堆积许多任务对象。客户端响应就会越来越慢,如果采用增加工作线程的方式,那么线程之间的切换将会大大消耗CPU。

    四、高效的半同步/半异步模型

    这种描述的半同步半异步模型,他的工作队列可以同时处理多个客户端连接。

    主线程只监听socket的事件,连接socket由工作线程来连接管理。当有新的连接的时候,主线程将之接受,并将其新返回的socket派发个某个工作线程,此后该连接上的所有I/O操作都由选中的工作线程来完成,直到客户端关闭。

    展开全文
  • 领导者/追随者模式是多个工作线程轮流获得事件源集合,轮流监听、分发并处理事件的一种模式。在任何时间点,只要一个领导者线程,他负责监听I/O事件。而其他线程则都是追随者,他们休眠在线程池中等待称为新的领导者...

    一、基本概念

    领导者/追随者模式是多个工作线程轮流获得事件源集合,轮流监听、分发并处理事件的一种模式。在任何时间点,只要一个领导者线程,他负责监听I/O事件。而其他线程则都是追随者,他们休眠在线程池中等待称为新的领导者。当前领导者如果检测到I/O事件,首先从线程池中推选出新的领导者线程,处理I/O事件。此时新的领导者等待新的I/O事件,而就得领导者则处理I/O事件,从而实现了并发。

    二、组成部分

    领导者/追随者模式下,主要由这几部分构成:句柄集、线程集、事件处理器和具体事件处理器。他们的关系如下:

    句柄集

      句柄用于表示I/O资源,在liunx下通常就是一个文件描述符,句柄集管理众多句柄,使用wait_for_event方法来监听这些句柄上的I/O事件,并将其中就绪事件通知给领导线程。领导者则调用绑定在Handle上的事件处理器来处理I/O事件。领导者将Handle绑定到事件处理器上的方法时register_handle。

    线程集

      这个组件是所有工作线程(包括领导者线程和追随者线程)的管理者,它主要负责线程的同步,以及线程新领导的推选。

    线程集中的线程在任一时间必处于如下三种状态:

    Leader:线程处于领导者,负责等待句柄集上的I/O事件

    Processing:线程正在处理事件,这状态下,推选出新的领导者,也可以指定其他追随者处理事件,此时领导者地位不变,如果处于Processing状态下的线程处理完事件,并且当前集中线程没有领导者,则他称为新的领导者,否则他直接变为追随者。

    Follower:线程处于追随者,调用join方法等待成为新的领导者,或者被当前领导者指定处理事件。

    状态转化图:

    事件处理器和具体事件处理器

    事件处理器通常包含一个或者多个回调函数handle_event。这些回调函数用于对应的业务逻辑。事件处理器在使用前就被绑定到某个句柄上,当事件发生的时候,领导者就会执行与之绑定的事件处理器中的回调函数。具体的事件处理器是事件处理器的派生类。他们必须重新实现基类中的handle_event方法,用于处理特定事件。

    工作流程如下:

    优点:领导者线程自己监听I/O事件并处理客户请求,因而领导者/追随者模式不需要像半同步/半异步模式一样,在线程之间同步访问请求队列。也不需要在线程之间传递任何额外数据。

    缺点:仅支持一个事件源集合,无法让每个线程独立管理多个客户连接。

     

    展开全文
  • 并发模式下,同步和异步的概念与I/O同步异步的概念有所不同,这里的同步是指程序按照代码的顺序执行,而异步指的是程序的执行需要系统事件来驱动,比如信号、中断等。 异步线程效率高,但编写相对复杂,难于调式...

    半同步/半异步模式

    在并发模式下,同步和异步的概念与I/O同步异步的概念有所不同,这里的同步是指程序按照代码的顺序执行,而异步指的是程序的执行需要系统事件来驱动,比如信号、中断等。

    异步线程效率高,但编写相对复杂,难于调式,而同步线程刚好相反,逻辑简单,但效率较差。
    半同步/半异步模式结合了同步线程和异步线程的优点,它在处理I/O事件时使用异步线程,处理客户逻辑则使用同步线程。这样既满足了客户连接的实时性,又能同时处理多个连接。
    实现半同步/半异步需要三个模块:异步处理模块、同步处理模块和队列模块。
    在实际的应用中,一般使用I/O复用epoll在主线程上监听客户端的连接,一旦监听到新的客户请求后,将其封装成请求对象,插入到队列中,同时,很多工作线程可以来读取并处理该请求对象。
    在这个模式中,最可能阻塞的操作放在同步模块中,这样不会影响到异步模块的处理,不同模块可以使用不同的同步策略,互不干扰,模块间通信则使用IPC实现,但这样则会造成同步模块和异步模块使用队列模块传送数据的时候,由于数据拷贝和上下文切换导致的性能开销。

    半同步/半反应堆模式

    半同步/半反应堆模式是半同步/半异步模式的一个变体,在半同步/半异步模式中,工作线程如何选择队列中的请求,是事先设计好的。而在半同步/半反应堆模式中,工作线程通过竞争(例如申请互斥锁)来获得任务的接管权。
    半同步/半反应堆可以采用Reactor模式,也可以采用Proactor模式处理,另外两种I/O模式的区别参考:I/O设计模式
    半同步/半反应堆中,异步线程是主线程,负责监听所有的socket事件,如果监听socket上有可读事件发生,指的是新的连接到来,那么异步线程接受它,插入到请求队列中,空闲工作线程开始竞争任务,之后这个线程管理这个socket的所有I/O任务,直到客户关闭连接,工作线程各自监听管理不同的事件,所以不需要通信,每个线程都是异步模式。
    缺点:对此进行队列操作是,都需要加锁解锁,从而消耗CPU事件,另外一个线程同一时间只能处理一个客户请求,如果队列中积累了很多任务,如果增加工作线程,工作线程的切换也会耗费大量CPU时间。
    改进:工作线程可以调用epoll_wait,这样一个工作线程也可以处理多个客户请求。

    领导者/追随者模式

    领导者/追随者模式是指多个工作线程轮流监听、分发、处理事件的一种模式。在任意事件,程序都仅有一个领导者线程,它负责监听I/O事件。其他线程都是追随者,他们休眠在线程池中等待新的领导者。当领导者检测到I/O事件时,首先从线程池中选出新的领导者线程,然后处理I/O事件。此时,新的领导者等待新的I/O事件,旧的领导者处理I/O事件,实现并发。
    领导者/追随者最大的优点在于,它是自己监听I/O事件并处理客户请求,也就是说从接收到处理都是在同一线程中完成,所以不需要在线程之间传递任何额外的数据,也不用在线程间同步对队列的访问。但也有一个明显的缺点,就是只支持一种事件源集合,所以导致它不能像其他模式让每个线程独立处理不同的客户请求。

    展开全文
  • 通过利用经典的模式可以使我们站在巨人的肩上,Half-Sync/Half-Async和Leader-Follower正是两种最经典的并发模式。 在实际中模式学习的难点往往在于好像看懂了,但是却总不能在正确的场景中使用。为了使大家能更好...
  • 高效模式: 在每个工作线程中利用epollO复用技术,可以同时监听多个事件,异步主线程负责监听链接事件,当事件到来后,传入到工作线程,工作线程将该socket注册到自己的epoll内核注册表中,这样,这样每个工作线程...
  • 一、高效并发模式(Reactor模式和Proactor模式) Reactor模式:主线程只负责监听文件描述符上是否有事件发生,有的话立即将该事情立即通知工作线程、除此之外,主线程不做任何其他是支持性的工作,读写数据,接受...
  • 具有可控模式高效并发功率放大器
  • 两种高效并发模式

    2019-02-27 00:34:34
    半同步/半异步模式 半同步/半异步模式中的同步和异步...在并发模式中,同步指的是程序完全按照代码序列的顺序执行,异步指的是程序的执行需要由系统事件来驱动。常见的系统事件包括中断 信号等。   按照同步...
  • 服务器两种高性能并发模式
  • 高并发的目的就是提高CPU的使用率,使得程序可以“同时...并发模式指的是I/O处理单元和多个逻辑单元协调完成任务的方法。有两种方法:半同步/半异步模式 和 领导者/追随者 模式。 半同步/半异步模式 这里的同步指的是程
  • Reactor模式,两种高效并发模式

    千次阅读 2016-09-20 21:10:55
    Reactor释义"反应堆",是一种事件驱动机制,和普通函数调用的不同之处在于,Reactor逆置了事件处理... Reactor简单的描述,就是当一件事情到时间了,那么他会自动执行。 Reactor模式的优点: (1)响应快,不必为单
  • 并发模式是指IO处理单元和多个逻辑单元之间协调完成任务的方法。服务器主要有两种并发编程模式:半同步/半异步 、领导者/追随者 模式 半同步/半异步 在IO模型中,同步和异步指的是是内核向应用程序是何种IO事件(是...
  • 结合考虑两种事件处理模式和几种I/O模型,半同步半异步存在多种变体,其中有一种变体是半同步半反应堆模式。 异步线程只有一个,由主线程来充当,它将监听套接字注册到epoll内核事件表中,如果监听套接字上有事件,...
  • 进程的出现使得程序交替执行成为可能,这就是所谓的并发, 并行就是在多个逻辑处理单元中同一时刻执行。 有时候也不要过于盲目的使用多进程或者多线程来实现并发,尤其在服务器编程的时候,因为如果程序是计算密集型...
  • 半同步/半异步模式、半同步/半反应堆模式、相对高效的半同步/半异步模式、领导者/追随者模式
  • 先解释一下同步和异步的区别,在并发模式中,这里的“同步"指的是程序完全按照代码的顺序执行,“异步”指的是程序的执行需要由系统事件来驱动,比如说信号、中断等。下图就清楚的解释了同步和异步操作的过程: ...
  • 半同步/半异步模式: 首先要区别于I/O模型中的同步异步: I/O模型中: 同步和异步是指内核向应用程序通知的是何种I/O事件(就绪事件/完成事件),以及该由谁来完成I/O读写(应用程序/内核);I/O模型中的同步和...
  • 一、并发模式中的同步和异步的区别 1、同步:程序完全按照代码顺序执行(简单理解就是,我调用一个功能该功能没有结束前,我就一直死等结果) 2、异步:程序的执行需要由系统事件来驱动,常见的系统事件包括中断、...
  • 并发模式是指I/O处理单元和多个逻辑单元之间协调完成任务的方法1、半同步/半异步模式1.1半同步/半异步模式【1】同步:程序完全按照代码顺序执行;异步:程序的执行需要由系统事件来驱动。常见的系统事件包括中断,...
  • 服务器编程基本框架: 事件处理模式 ...一般来说,IO复用机制都需要...Reactor模式是指主线程只负责监听文件描述符上是不是有事件发生,有的话就将该事件通知工作线程,除此之外,主线程不需要做其他任何工作,其
  • 一、并发编程与并发模式并发编程主要是为了让程序同时执行多个任务,并发编程对计算精密型没有优势,反而由于任务的切换使得效率变低。如果程序是IO精密型的,则由于IO操作远没有CPU的计算速度快,所以让程序阻塞于...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 697
精华内容 278
关键字:

高效并发模式