本文目录导读:

- 使用 threading.Lock(线程安全)
- 使用 multiprocessing.Lock(进程安全)
- 使用 asyncio.Lock(异步安全)
- 使用 Redis 实现分布式锁(跨进程/跨机器)
- 使用 cachetools 库(推荐)
- 最佳实践建议
在Python中控制并发缓存写入,有几种常用方法:
使用 threading.Lock(线程安全)
import threading
import time
from functools import lru_cache
class ThreadSafeCache:
def __init__(self):
self.cache = {}
self.lock = threading.Lock()
def get(self, key):
with self.lock:
return self.cache.get(key)
def set(self, key, value):
with self.lock:
self.cache[key] = value
def update_if_absent(self, key, compute_func):
"""如果缓存中没有,则计算并写入"""
with self.lock:
if key not in self.cache:
self.cache[key] = compute_func()
return self.cache[key]
# 使用示例
cache = ThreadSafeCache()
def expensive_operation(key):
time.sleep(1) # 模拟耗时操作
return f"result_{key}"
# 在多个线程中使用
def worker(key):
result = cache.update_if_absent(key, lambda: expensive_operation(key))
print(f"Got result: {result}")
使用 multiprocessing.Lock(进程安全)
import multiprocessing
import time
class ProcessSafeCache:
def __init__(self):
self.manager = multiprocessing.Manager()
self.cache = self.manager.dict()
self.lock = multiprocessing.Lock()
def get(self, key):
with self.lock:
return self.cache.get(key)
def set(self, key, value):
with self.lock:
self.cache[key] = value
def worker(cache, key):
# 双重检查锁(Double-checked locking)
result = cache.get(key)
if result is None:
with cache.lock:
# 再次检查,防止重复计算
result = cache.get(key)
if result is None:
time.sleep(1) # 模拟耗时操作
result = f"result_{key}"
cache.set(key, result)
print(f"Process got: {result}")
if __name__ == '__main__':
cache = ProcessSafeCache()
processes = []
for i in range(5):
p = multiprocessing.Process(target=worker, args=(cache, "key1"))
processes.append(p)
p.start()
for p in processes:
p.join()
使用 asyncio.Lock(异步安全)
import asyncio
from functools import lru_cache
class AsyncCache:
def __init__(self):
self.cache = {}
self.lock = asyncio.Lock()
async def get(self, key):
async with self.lock:
return self.cache.get(key)
async def set(self, key, value):
async with self.lock:
self.cache[key] = value
async def get_or_compute(self, key, compute_func):
async with self.lock:
if key not in self.cache:
self.cache[key] = await compute_func()
return self.cache[key]
async def expensive_async_operation(key):
await asyncio.sleep(1) # 模拟异步耗时操作
return f"async_result_{key}"
async def main():
cache = AsyncCache()
# 并发执行多个协程
tasks = [
cache.get_or_compute("key1", lambda: expensive_async_operation("key1"))
for _ in range(3)
]
results = await asyncio.gather(*tasks)
print(f"Results: {results}")
asyncio.run(main())
使用 Redis 实现分布式锁(跨进程/跨机器)
import redis
import time
import uuid
class RedisDistributedCache:
def __init__(self, redis_client, lock_timeout=10):
self.redis = redis_client
self.lock_timeout = lock_timeout
def acquire_lock(self, lock_name, acquire_timeout=5):
"""获取分布式锁"""
identifier = str(uuid.uuid4())
end = time.time() + acquire_timeout
while time.time() < end:
if self.redis.setnx(f"lock:{lock_name}", identifier):
self.redis.expire(f"lock:{lock_name}", self.lock_timeout)
return identifier
time.sleep(0.001)
return None
def release_lock(self, lock_name, identifier):
"""释放分布式锁"""
# 使用 Lua 脚本确保原子操作
lua_script = """
if redis.call("get", KEYS[1]) == ARGV[1] then
return redis.call("del", KEYS[1])
else
return 0
end
"""
self.redis.eval(lua_script, 1, f"lock:{lock_name}", identifier)
def get_or_compute(self, key, compute_func, ttl=3600):
"""获取缓存或计算"""
# 先尝试读取缓存
cached = self.redis.get(key)
if cached:
return cached.decode()
# 获取锁
lock_id = self.acquire_lock(key)
if lock_id:
try:
# 双重检查
cached = self.redis.get(key)
if cached:
return cached.decode()
# 计算并缓存
result = compute_func()
self.redis.setex(key, ttl, result)
return result
finally:
self.release_lock(key, lock_id)
else:
# 无法获取锁,等待或重试
time.sleep(0.1)
return self.get_or_compute(key, compute_func, ttl)
# 使用示例
redis_client = redis.Redis(host='localhost', port=6379, db=0)
distributed_cache = RedisDistributedCache(redis_client)
def expensive_computation(x):
time.sleep(2)
return x * x
# 模拟并发调用
result = distributed_cache.get_or_compute("calc_5", lambda: expensive_computation(5))
print(f"Result: {result}")
使用 cachetools 库(推荐)
from cachetools import cached, TTLCache
import threading
import time
# 创建线程安全的 TTL 缓存
cache = TTLCache(maxsize=100, ttl=300) # 300秒过期
@cached(cache, lock=threading.Lock())
def expensive_function(key):
"""自动处理并发的缓存读写"""
time.sleep(1) # 模拟耗时操作
return f"result_{key}"
# 多线程并发调用
def worker(key):
result = expensive_function(key)
print(f"Thread got: {result}")
threads = []
for i in range(3):
t = threading.Thread(target=worker, args=("test_key",))
threads.append(t)
t.start()
for t in threads:
t.join()
最佳实践建议
-
选择合适的锁类型:
- 单进程多线程:
threading.Lock - 多进程:
multiprocessing.Lock或 Redis - 异步IO:
asyncio.Lock - 分布式系统:Redis 或 Zookeeper
- 单进程多线程:
-
使用双重检查锁:减少锁竞争,提高性能
-
设置合理的超时时间:防止死锁
-
考虑缓存雪崩/穿透:
- 使用布隆过滤器
- 设置随机过期时间
- 限流降级
-
监控和告警:添加缓存命中率、锁等待时间等监控指标
选择哪种方案取决于你的具体场景:并发级别、数据一致性要求、系统架构等因素。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播