V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
mahone3297
V2EX  ›  Go 编程语言

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

  •  
  •   mahone3297 · 2015-12-02 16:28:25 +08:00 · 1981 次点击
    这是一个创建于 3258 天前的主题,其中的信息可能已经有所发展或是发生改变。
    上一下代码


    我的疑问:
    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 ?但是值又都有。这是为什么?
    14 条回复    2015-12-03 10:53:07 +08:00
    9hills
        1
    9hills  
       2015-12-02 16:53:32 +08:00
    m[key] += 1
    这个最后的累加结果和执行顺序无关,所以累加后的值应该是精确的
    zzn
        2
    zzn  
       2015-12-02 17:07:35 +08:00
    m 要加锁
    zealot0630
        3
    zealot0630  
       2015-12-02 17:41:45 +08:00
    go routine 是非抢占的 意味着所有基本操作(非 syscall )都是原子的

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

    https://gobyexample.com/mutexes

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

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

    如果只是一个 Int 的话,可以用 Atomic ,我上面帖的例子里也有。但是不知道是不是 atomic 和 mutex 必须结合起来一起用。(我记得只要用 mutex 锁上就好了,不知道记忆是否准确)
    mahone3297
        9
    mahone3297  
    OP
       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
        10
    msg7086  
       2015-12-02 22:08:48 +08:00   ❤️ 1
    @mahone3297 at 自己表示编辑补充,属于惯例用法。
    多数是发现自己上一段没说完整或者没说正确,所以提醒别人下一段是承接、修正上一段的。
    pubby
        11
    pubby  
       2015-12-02 22:21:21 +08:00
    map 并发读写要上锁,碰到过冲突 panic 的

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

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

    你的响应中 %d 只有 1-9 的时候 长度才是一样的,后面都跟第一次不一样,所以全部 failed 了
    mahone3297
        13
    mahone3297  
    OP
       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
        14
    pubby  
       2015-12-03 10:53:07 +08:00 via Android
    @mahone3297 可以试试。%010d
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2714 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 40ms · UTC 08:32 · PVG 16:32 · LAX 01:32 · JFK 04:32
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.