1. 前情回顾
Go语言提供了goroutine来简单的实现并发,对于我这种不太喜欢动脑子的人来说这是一个非常完美的方式。而且其原理易于理解,只要稍有一点计算机的基础知识就可以轻松地理解其调度机制。
并发编程很重要的一点就是线程间的通信,这一点在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语言也是边翻书边敲代码,到现在也是写了几个小工具了,效果还不错。但是这种学习方式总是让基础比较薄弱,有些地方研究思考的不是很到位。
因此未来还是从最基础的变量等等学起吧。
网友评论