三種方法來實現
-
lpop的 原子操作 10個商品就 lpush 10個數據 搶購開始用lpop來判斷是否還存在庫存
-
watch實現 下面有代碼實現
watch庫存鍵, multi後如果該key被其他客戶端改變, 事務操作會拋出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