鍍金池/ 問(wèn)答/人工智能  PHP/ redis原子性測(cè)試的疑問(wèn)

redis原子性測(cè)試的疑問(wèn)

我知道redis的單個(gè)操作是原子性的,如果在代碼中對(duì)redis進(jìn)行多次操作將無(wú)法保證整個(gè)操作流程的原子性。

比如下面的這段代碼中,假設(shè)nums這個(gè)key的值是50,使用ab.exe工具對(duì)其1000次訪問(wèn),并發(fā)數(shù)是100,理論上結(jié)果應(yīng)該會(huì)出現(xiàn)負(fù)數(shù)的.

可是我多次測(cè)試下nums的值都是1,請(qǐng)問(wèn)是我測(cè)試的方式不對(duì)還是其他哪里有問(wèn)題呢?

$nums = $redis->get('nums');
if($nums > 1)
    $redis->decr('nums');
回答
編輯回答
葬愛(ài)

不知道ab.exe測(cè)試時(shí)什么原理,你自己寫一個(gè)多線程調(diào)用下就知道了會(huì)產(chǎn)生負(fù)數(shù)值的。

//php不會(huì),用java寫了個(gè)test。
import redis.clients.jedis.Jedis;


public class Test {
    
    public static void main(String[] args) throws Exception {
        
        Jedis jedis = getJedis();
        jedis.set("nums", 50+"");
        close(jedis);
        
        for(int i = 0;i < 1000;i++){ //啟動(dòng)1000個(gè)線程
            new Thread(new MyTask()).start();
        }
        
    }
    
    public static  Jedis getJedis(){
        Jedis j = new Jedis("xxxxx", 6379);
        j.auth("xxxx");
        return j;
    }
    
    public static void close(Jedis jedis){
        if(null == jedis){
            return;
        }
        jedis.close();
    }
}

class MyTask implements Runnable{
    @Override
    public void run() {
        Jedis j = Test.getJedis();
         String numStr = j.get("nums");
         Integer nums = Integer.valueOf(numStr);
        
        if(nums > 1){
             j.decr("nums");
        }else{
             System.out.println(nums);
        }
        Test.close(j);
    }
}

輸出結(jié)果出現(xiàn)負(fù)值。

2018年1月23日 09:46
編輯回答
葬愛(ài)

你寫了判斷呀,大于1的時(shí)候才遞減1
你減到1的時(shí)候都不執(zhí)行了,他怎么能作為測(cè)試原子性的依據(jù)呢?

2018年5月23日 09:24
編輯回答
孤客

你這樣的并發(fā)很難測(cè)試出來(lái)的,的確這樣操作存在負(fù)數(shù)的可能。但是想想你的電腦是 4核8線程,最多同時(shí)執(zhí)行8個(gè)請(qǐng)求而已,這對(duì)redis來(lái)說(shuō)是非常小的并發(fā)量了。所以我認(rèn)為不出現(xiàn)問(wèn)題是因?yàn)椴l(fā)量小了,實(shí)際上是會(huì)存在問(wèn)題的。

2017年1月24日 11:44