周记7

记一次Go slice在并发中不安全的坑

当时的软件结构是,系统启动后会启动n个 goroutine, 然后所有的goroutine等待Task的到来,并发的处理多个task。

在task到来的时候,进行相关参数的拼接(故障就出在这),然后调用shell 执行命令

1
2
3
4
5
6
7
8
9
10
11
12
// 获取参数与参数拼接代码
params = rsync.params

params = buildParms(params, src, dst)

exec(params)


func buildParams(params, src, dst) []string {
params = append(...)
return params
}

代码执行之后,当并发量比较大的时候,会发现 build之后的params 的最后几个字符串会异常

知道是并发slice线程安全的问题,但是解决办法,百思不得其解

后来问题聚焦于append ,google 证实append的确不是一个线程安全的函数,并发执行直接的话,会导致data race

在go playground 中 :发现了一点起色,就是

buildParams 函数 每次新建一个新的 slice 然后 返回新的 slice

结果发现 现象的确少了很多,但是还是有

后来发现,只要 在调用上层 也新建slice 就可以完全规避这个问题。

也就是不要在并发的时候 公用一个 slice 一定要每次操作都进行新建。

1
2
3
4
5
6
7
8
9

// 改进之后的 拼装参数方法
func buildParams(params []string, src string, dst string) []string {
s := make([]string, 0)
s = append(s, params...)
s = append(s, src)
s = append(s, dst)
return s
}

Go

goland vendor 不识别

goland不会识别 vendor 文件夹下的相关dep

所以 可以使用 文件夹下带 src目录,然后添加到 project PATH 就可以正常的代码提示

Go 跨平台编译

用于减少开发成本 build 了之后 直接 rsync上去

CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o

Go 不能 在exec shell的时候直接 cd

cmd.Dir = “/“

map 非线程安全 增删改查需要 加锁

信号量 控制并发数量

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
34
package utils

import "sync"

type Semaphore struct {
maxNum int
Threads chan int
Wg sync.WaitGroup
}

func NewSemaphore (maxNum int) *Semaphore {
var sem = new(Semaphore)
sem.maxNum = maxNum
sem.Threads = make(chan int, maxNum)
return sem
}

func (sem *Semaphore) P() {
sem.Threads <- 1
sem.Wg.Add(1)
}

func (sem *Semaphore) V() {
sem.Wg.Done()
<-sem.Threads
}

func (sem *Semaphore) Wait() {
sem.Wg.Wait()
}

func (sem *Semaphore) Discard() {
sem.Threads = make(chan int, sem.maxNum)
}

PHP

脚本中存在死循环的调用

有一个类 里面有各种方法 外加一个 死循环 的 check方法

在其他方法调用这个类的其他方法的时候 Class::otherMethod();

fpm 出现了504

百思不得其解

phpunit测试发现,在调用static方法的时候,竟然连 check()方法一起执行了你敢信?

所以 执行和类 需要分开

原文地址:https://www.cnblogs.com/xiaoerli520/p/9624345.html