默认的 http 那一套,是否保证了原子性?

2015-12-02 16:28:25 +08:00
 mahone3297
上一下代码


我的疑问:
1. 我用 ab -c 10 -n 100000 'http://192.168.81.130:8080/increase?key=user&count=1' 去压, server 端,应该是多 go routine 去处理, m 应该是保证不了原子性的吧?但是我的出来的值,却是
curl 'http://192.168.81.130:8080/debug'
debug v = map[user:100000]
很精准的值 100000 。。。测了多次都是。。。
所以,问题,是这个 http 包保证了?还是 map 保证了?还是其他?
我是否要用 https://golang.org/pkg/sync/atomic/ 包去保证原子性?

2. ab 的结果,如下图

Failed requests: 99991 有这么多 failed ?但是值又都有。这是为什么?
2035 次点击
所在节点    Go 编程语言
14 条回复
9hills
2015-12-02 16:53:32 +08:00
m[key] += 1
这个最后的累加结果和执行顺序无关,所以累加后的值应该是精确的
zzn
2015-12-02 17:07:35 +08:00
m 要加锁
zealot0630
2015-12-02 17:41:45 +08:00
go routine 是非抢占的 意味着所有基本操作(非 syscall )都是原子的

然而,你这个程序冲突概率太低了,即使使用 java/C++这种语言 跑个几天大概能冲突一次吧
martifact
2015-12-02 18:07:58 +08:00
都不能保证。这个场景下 routine 之间的数据并发应该跟核数有关,概率确实挺低。
yinheli
2015-12-02 18:16:32 +08:00
1. 程序执行太快了. 要想模拟冲突, 应该先取出值, 然后随机 sleep 一会, 1 毫秒, 都够
2. `failed` 是因为你的响应, 不一致. ab 判断长度不同导致的
fwee
2015-12-02 20:13:04 +08:00
说版本, 1.5 之前默认是单核的协作式,这个结果正常
raincious
2015-12-02 20:23:51 +08:00
读公共数据的时候需要建立一个 mutex 来锁,否则铁定冲突。

https://gobyexample.com/mutexes

想看冲突的话, 1.4 以及之前需要用 runtime.GOMAXPROCS 来使用多个核心。
raincious
2015-12-02 20:26:55 +08:00
@raincious

修改,不仅仅是读,写的时候也要锁。详见 Golang 的 Sync 包: https://golang.org/pkg/sync/

如果只是一个 Int 的话,可以用 Atomic ,我上面帖的例子里也有。但是不知道是不是 atomic 和 mutex 必须结合起来一起用。(我记得只要用 mutex 锁上就好了,不知道记忆是否准确)
mahone3297
2015-12-02 22:05:15 +08:00
@9hills
》 m[key] += 1
》这个最后的累加结果和执行顺序无关,所以累加后的值应该是精确的
光是这样写,应该也是保证不了原子性的,所以才会有 atomic 库,这个页面中的例子就谈到了这样的情况
https://golang.org/pkg/sync/atomic/


@zzn 嗯,应该要加 atomic

@zealot0630 同上,这个加,应该是非原子的,看下这个库的介绍
https://golang.org/pkg/sync/atomic/

@martifact 确实,本来概率就低,我还虚拟机,分配的单核。。。看来环境也有问题


@yinheli
》 1. 程序执行太快了. 要想模拟冲突, 应该先取出值, 然后随机 sleep 一会, 1 毫秒, 都够
确实,说的有道理,考虑试试,谢谢指点。
2. `failed` 是因为你的响应, 不一致. ab 判断长度不同导致的
》这个不太明白,再解释下?

@fwee
最新版本, 1.5.1

@raincious
谢谢例子!好好研究下。
再问下,我们有些人,第 2 个回复的时候,会 @自己,这有什么好处吗?
msg7086
2015-12-02 22:08:48 +08:00
@mahone3297 at 自己表示编辑补充,属于惯例用法。
多数是发现自己上一段没说完整或者没说正确,所以提醒别人下一段是承接、修正上一段的。
pubby
2015-12-02 22:21:21 +08:00
map 并发读写要上锁,碰到过冲突 panic 的

另外提一下<map>有意思的地方
for i,_ := range <map> {
delete(<map>,i)
}

并不会影响 iterator 过程
pubby
2015-12-02 22:31:27 +08:00
ab 测试的时候,返回的内容长度不同,就会 failed

你的响应中 %d 只有 1-9 的时候 长度才是一样的,后面都跟第一次不一样,所以全部 failed 了
mahone3297
2015-12-03 09:48:10 +08:00
@pubby
>map 并发读写要上锁,碰到过冲突 panic 的
>另外提一下<map>有意思的地方
for i,_ := range <map> {
delete(<map>,i)
}
>并不会影响 iterator 过程
有点意思。。。

>ab 测试的时候,返回的内容长度不同,就会 failed
>你的响应中 %d 只有 1-9 的时候 长度才是一样的,后面都跟第一次不一样,所以全部 failed 了
原来是这样啊。。。了解了。他是要每个请求的返回长度都一样啊。那我这样的案例,如果测试请求是否成功呢?按照 ab 的逻辑,不行了。他干嘛不看返回的 http code 呢,真见鬼。
pubby
2015-12-03 10:53:07 +08:00
@mahone3297 可以试试。%010d

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/240605

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX