Golang Go语言中默认的 http 那一套,是否保证了原子性?

发布于 1周前 作者 vueper 来自 Go语言

上一下代码


我的疑问:
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 ?但是值又都有。这是为什么?
Golang Go语言中默认的 http 那一套,是否保证了原子性?


更多关于Golang Go语言中默认的 http 那一套,是否保证了原子性?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

15 回复

m[key] += 1
这个最后的累加结果和执行顺序无关,所以累加后的值应该是精确的

更多关于Golang Go语言中默认的 http 那一套,是否保证了原子性?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


go routine 是非抢占的 意味着所有基本操作(非 syscall )都是原子的

然而,你这个程序冲突概率太低了,即使使用 java/C++这种语言 跑个几天大概能冲突一次吧

都不能保证。这个场景下 routine 之间的数据并发应该跟核数有关,概率确实挺低。

  1. 程序执行太快了. 要想模拟冲突, 应该先取出值, 然后随机 sleep 一会, 1 毫秒, 都够
    2. failed 是因为你的响应, 不一致. ab 判断长度不同导致的

说版本, 1.5 之前默认是单核的协作式,这个结果正常

读公共数据的时候需要建立一个 mutex 来锁,否则铁定冲突。

https://gobyexample.com/mutexes

想看冲突的话, 1.4 以及之前需要用 runtime.GOMAXPROCS 来使用多个核心。



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

如果只是一个 Int 的话,可以用 Atomic ,我上面帖的例子里也有。但是不知道是不是 atomic 和 mutex 必须结合起来一起用。(我记得只要用 mutex 锁上就好了,不知道记忆是否准确)


》 m[key] += 1
》这个最后的累加结果和执行顺序无关,所以累加后的值应该是精确的
光是这样写,应该也是保证不了原子性的,所以才会有 atomic 库,这个页面中的例子就谈到了这样的情况
https://golang.org/pkg/sync/atomic/


嗯,应该要加 atomic

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

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



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


最新版本, 1.5.1


谢谢例子!好好研究下。
再问下,我们有些人,第 2 个回复的时候,会 自己,这有什么好处吗?

at 自己表示编辑补充,属于惯例用法。
多数是发现自己上一段没说完整或者没说正确,所以提醒别人下一段是承接、修正上一段的。

map 并发读写要上锁,碰到过冲突 panic 的

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

并不会影响 iterator 过程

ab 测试的时候,返回的内容长度不同,就会 failed

你的响应中 %d 只有 1-9 的时候 长度才是一样的,后面都跟第一次不一样,所以全部 failed 了


>map 并发读写要上锁,碰到过冲突 panic 的
>另外提一下<map>有意思的地方
for i,_ := range <map> {
delete(<map>,i)
}
>并不会影响 iterator 过程
有点意思。。。

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

可以试试。%010d

在Golang中,HTTP包提供的默认路由处理机制并不直接保证原子性。原子性通常是指在多线程并发访问下,对一个或多个变量的一系列操作要么全部执行,要么都不执行,不存在不完整的情况。这通常通过特定的同步原语或硬件指令来实现。

HTTP包主要处理的是网络请求和响应,它使用goroutine来实现高并发处理,但并没有直接提供对变量操作的原子性保证。如果在处理HTTP请求时需要对共享变量进行并发访问,开发者需要使用额外的同步机制来确保原子性,例如使用sync/atomic包中的原子操作函数,或者使用sync包中的Mutex等同步原语。

因此,对于Golang中的HTTP处理,如果需要在并发环境下保证对共享变量的原子性操作,开发者需要自行实现相应的同步机制。这通常涉及到对共享变量的访问进行加锁或使用原子操作,以确保在并发访问时不会出现数据竞争和不一致的问题。

总的来说,Golang的HTTP包本身并不提供原子性保证,但开发者可以通过使用sync/atomic包或sync包中的同步原语来实现所需的原子性操作。

回到顶部