redisトランザクションマルチプロセスシミュレーション秒殺在庫を保証する正しいluaスクリプトとwatchの方法


3つの方法で実現
  • lpopの原子操作10個の商品についてlpush 10個のデータ買い占め開始についてlpopで在庫
  • がまだ存在するか否かを判断する.
  • watchインプリメンテーションの下には、コードインプリメンテーションwatchの在庫キーがあり、multi後にキーが他のクライアントによって変更されると、トランザクション操作はWatchError異常
  • を放出する.
  • luaスクリプトの下にコード実装
  • があります.

    watchメソッド実装

    import redis
    from redis import WatchError
    from concurrent.futures import ProcessPoolExecutor
    
    r = redis.Redis(host='127.0.0.1', port=6379, password='123')
    
    
    #      ,          
    #     ,      ,   True
    #     ,      ,   False
    def decr_stock():
    
        # python redis     pipeline      
        with r.pipeline() as pipe:
            while True:
                try:
                    # watch   , multi    key        ,        WatchError  
                    pipe.watch('stock:count')
                    count = int(pipe.get('stock:count'))
                    if count > 0:  #    
                        #     
                        pipe.multi()
                        pipe.decr('stock:count')
                        #        
                        # execute          ,       decr     
                        print pipe.execute()[0]
                        return True
                    else:
                        return False
                except WatchError, ex:
                    #   WatchError  ,    watch     
                    print ex
                    pipe.unwatch()
    
    
    def worker():
        while True:
            #        
            if not decr_stock():
                print "=============="
                break
    
    
    #     
    #      100
    r.set("stock:count", 100000)
    print r.get("stock:count")
    import time
    testa = time.time()
    #             
    with ProcessPoolExecutor(max_workers=5) as pool:
        for _ in range(10):
            pool.submit(worker)
    print time.time() - testa
    

    luaスクリプトのメソッド実装

    import redis
    from redis import WatchError
    from concurrent.futures import ProcessPoolExecutor
    
    r = redis.Redis(host='127.0.0.1', port=16379, password='joyame!@#')
    
    
    #      ,          
    #     ,      ,   True
    #     ,      ,   False
    def decr_stock():
       lua_2 = """
            if (tonumber(redis.call("GET","stock:count")) > tonumber(0)) then
                redis.call("DECR","stock:count")
                return true
            else
                return nil
            end
            """
    
        # python redis     pipeline      
        with r.pipeline() as pipe:
            while True:
                try:
                    script_2 = r.register_script(lua_2)
                    a = script_2()
                    if a >= 0:
                        print a
                        return True
                    else:
                        return False
    
                except WatchError, ex:
                    #   WatchError  ,    watch     
                    print ex
                    pipe.unwatch()
    
    
    def worker():
        while True:
            #        
            if not decr_stock():
                print "=============="
                break
    
    
    #     
    #      100
    r.set("stock:count", 1000)
    
    import time
    testa = time.time()
    #             
    with ProcessPoolExecutor(max_workers=5) as pool:
        for _ in range(10):
            pool.submit(worker)
    print time.time() - testa