Go sync.RWMutex - 解决并发读写问题(转)

转自: https://github.com/gocn/translator/blob/master/2019/w13_sync_mutex_translation.md

sync.RWMutex - 解决并发读写问题

当多个线程访问共享数据时,会出现并发读写问题(reader-writer problems)。有两种访问数据的线程类型:

  • 读线程 reader:只进行数据读取
  • 写线程 writer:进行数据修改

当 writer 获取到数据的访问权限后,其他任何线程(reader 或 writer)都无权限访问此数据。这种约束亦存在于现实中,比如,当 writer 在修改数据无法保证原子性时(如数据库),此时读取未完成的修改必须被阻塞,以防止加载脏数据(译者注:数据库中的脏读)。还有许多诸如此类的核心问题,例如:

  • writer 不能无限等待
  • reader 不能无限等待
  • 不允许线程出现无限等待

Go time.Parse 方法问题记录

问题

在go项目中使用 time.Parse()把字符串转成日期后,内部的loc信息为nil,这时用来和time.Now()进行日期比较或者获取Unix值时,都与预期的结果不匹配。

解决方法

使用time.ParseInLocation()代替time.Parse()

1
2
timePoint,_ := time.ParseInLocation("2006-01-02 15:04:05","2019-04-09 00:00:00",time.Local)
fmt.Println(timePoint)

Go 利用链表实现循环队列

记录下使用Go语言,利用silce实现循环队列。

本文代码github: https://github.com/zboyco/go-test/tree/master/queue/link

需要slice实现队列可以参考:
Go 利用slice实现循环队列


1. 列举一下准备实现的功能列举一下准备实现的功能

这里只使用单向链表实现队列功能,实现下列方法:

  • Enqueue 入队
  • Dequeue 出队

使用链表实现队列相比较slice的优势是,队列容量可以不受限制。(当然也可以在结构体中增加容量和长度字段,限制队列长度)

2. 实现代码

Go 利用slice实现循环队列

记录下使用Go语言,利用silce实现循环队列。

本文代码github: https://github.com/zboyco/go-test/tree/master/queue/slice

需要链表实现队列可以参考:
Go 利用链表实现循环队列


1. 列举一下准备实现的功能列举一下准备实现的功能

  • InitQueue 初始化队列
  • Lenght 获取当前队列长度
  • IsFull 是否满
  • IsEmpty 是否空
  • EnQueue 入队
  • DeQueue 出队

队列使用slice作为存储数据的容器,使用slice而不使用array的原因是想在初始化的时候再指定队列长度,提高灵活性.

2. 简单实现:

Go 单元测试

本文代码github地址: https://github.com/zboyco/goutlis/blob/master/encry/md5_test.go


Go 编写单元测试

go 的单元测试编写很简单,记录一下下面几个点.

  1. 测试文件必须使用_test.go结尾,比如:md5_test.go .

  2. 导入testing包 .

  3. 测试方法名使用Test开始,比如TestMD5 .

  4. 接收一个testing.T类型的指针参数 .
    e.g.

    1
    func TestMD5(t *testing.T)
  5. 主要使用的Log方法

    1
    2
    3
    t.Log
    t.Fatal
    t.Error
  6. 测试方法

    1
    go test -v
  • -v用于输出日志,不使用-v的话将只显示结果

Go Visual Studio Code运行配置

在vscode中debug Go语言程序,需要配置launch.json文件
先贴出文件代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Launch",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceRoot}",
"env": {
"GOPATH":"C:/Users/baiyang/go;C:/Users/baiyang/Source/repos/go;"
},
"args": []
}
]
}

其中主要注意的是programenv属性.

  • program修改为${workspaceRoot},指从当前项目根目录运行
  • env默认为空,需要添加GOPATH路径,系统中有多个GOPATH的话就添加多个即可

配置好launch.json后就可以直接在vscode中运行和调试go程序了

Go 日期格式化

go语言日期格式话格式比较奇怪

记忆就是 1,2,3,4,5,6
1 代表 月份
2 代表 号数
3 代表 小时
4 代表 分钟
5 代表 秒数
6 代表 年份

1
2
currentTime := time.Now()
value = currentTime.Format("2006/01/02 15:04:05")

Go 状态枚举实例

Go 没有单独的枚举类型,采用const实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package status

const (
OK = 0 // 正常
UnknowError = 100 // 未知错误
UserNotExist = 101 // 用户不存在
UserExist = 102 // 用户已存在
CodeNoExist = 103 // 验证码不存在
CodeError = 104 // 验证码不正确
UserError = 105 // 用户名或密码错误
InnerError = 199 // 内部错误
)

var statusText = map[int]string{
OK: "",
UnknowError: "未知错误",
UserNotExist: "用户不存在",
UserExist: "用户名已被注册",
CodeNoExist: "验证码不存在或已过期,请重新获取验证码",
CodeError: "验证码不正确",
UserError: "用户名或密码错误",
InnerError: "内部错误: ",
}

// Message 返回错误消息
func Message(code int) string {
str, ok := statusText[code]
if ok {
return str
}
return statusText[UnknowError]
}