Go语言之通道(二)

1. 前情回顾

Go语言提供了goroutine来简单的实现并发,对于我这种不太喜欢动脑子的人来说这是一个非常完美的方式。而且其原理易于理解,只要稍有一点计算机的基础知识就可以轻松地理解其调度机制。

并发编程很重要的一点就是线程间的通信,这一点在Go语言中也可以通过通道这个东西轻松地完成。

下面是我之前写的笔记的链接:

Go语言之通道(一)

我也就不再过多的表述通道的问题了。

2. 今天要讲的事情

我是一个DBA,当我在学习到通道的时候,我内心总是觉得这个东西很像MySQL的传统复制。

  • Master将事务写在binlog中,通知slave来取;
  • Slave接到通知,将binlog转录会本地的relaylog中;
  • Slave上有一个SQL线程负责将中继日志重放。

因此我只需要启动一个goroutine一直写binlog到通道里,另外一个goroutine一直接收这个通道传来的binlog就可以了。

那么下面就可以着手编码了:

package main

import (
    "fmt"
    "time"
)

type binlog struct {
    id int
    event string
}

var i = 1

func main() {
    transaction := make(chan binlog)
    ack := make(chan string)
    go master(transaction)
    go slave(transaction, ack)
    for {
        <- ack
    }
}

func master(transaction chan binlog) {
    for {
        //发送binlog
        transaction <- binlog{id:i, event: "commit"}
        //为了好打印观察结果,每次给通道一个值就休息1s
        time.Sleep(1 * time.Second)
        i++
    }
}

func slave(transaction chan binlog, ack chan string) {
    for {
        relaylog := <-transaction
        fmt.Printf("get binlog: %d, event is %s\n", relaylog.id, relaylog.event)
        ack <- "ok"
    }
}

这样就模拟了复制的过程:

复制模拟

然而要注意的是,我这里用的是无缓冲通道。这种通道的问题是,发送会被阻塞,直到另一个goroutine通道执行接收操作并完成。

这其实就是一个同步的过程,MySQL的复制,从来都是异步的。因此需要选择的并不是无缓冲通道来模拟,而要选择缓存通道,则比较地道。

其实代码改动起来比较简单,只需要将main函数的这里替换一下就可以:

transaction := make(chan binlog, 100)

缓冲通道的一个好处是通道关闭了以后,还是可以继续的取到通道中的值,有了这个保证,如果Master在发送完成后将通道关闭了,其实Slave还是可以接收到binlog的。这个我在之前的笔记中也是介绍过的。

3. 小结

我学Go语言,其实完全是为了开发一些帮助我完成日常DBA工作的小工具,最开始我用的是Python,这门语言上手极快,但是用完语法基本全忘,下次再开发工具的时候继续百度或者翻书。

而且我们的内网开发环境是不允许连接外网的,因此Python的很多依赖包都没有办法用pip安装,这一点让人很头疼。不过还好我遇到了Go语言。

出于我的学习初衷,我学习Go语言也是边翻书边敲代码,到现在也是写了几个小工具了,效果还不错。但是这种学习方式总是让基础比较薄弱,有些地方研究思考的不是很到位。

因此未来还是从最基础的变量等等学起吧。

你可能感兴趣的:(Go语言之通道(二))