Python线程锁

多线程用于IO、网络请求等地方,只要不是CPU密集型,都可以直接使用多线程。

线程锁在代码中发挥着关键的保护作用,让我详细解释它的工作原理:

锁的作用机制

1. 基本工作原理

with lock:
    if ensp_id in ensp_to_seq:
        return True

执行流程

  • 线程A进入with lock:块,获取锁
  • 线程A检查ensp_id是否在字典中
  • 在此期间,线程B尝试进入同一个with lock:块,但被阻塞等待
  • 线程A完成检查后退出with块,自动释放锁
  • 线程B现在可以获取锁并进入临界区

2. 为什么需要锁?

没有锁的情况(竞态条件)

# 线程A检查 ensp_id 不在字典中
if ensp_id not in ensp_to_seq:  # 假设此时不在

# 在线程A发起请求前,线程B也检查同一个ensp_id
# 线程B也发现不在字典中,也发起请求

# 结果:同一个ensp_id被请求了两次!

有锁的情况

with lock:
    if ensp_id in ensp_to_seq:  # 线程A检查,获取锁
        return True
    # 线程A释放锁,发起请求...

# 线程B必须等待线程A完成检查才能进入

3. 完整的线程安全流程

def get_ensembl_sequence(ensp_id: str):
    # 第一步:检查是否存在(需要锁保护)
    with lock:
        if ensp_id in ensp_to_seq:  # 原子性操作
            return True
    
    # 第二步:网络请求(不需要锁,可以并行执行)
    headers = {"Content-Type": "text/x-fasta", "Accept": "text/x-fasta"}
    try:
        response = requests.get(url, headers=headers)
        response.raise_for_status()
        seq = response.text.strip()
        seq = "".join(seq.split("\n")[1:])
        
        # 第三步:写入结果(需要锁保护)
        with lock:
            ensp_to_seq[ensp_id] = seq  # 原子性操作
            print(len(ensp_to_seq))
        return True
    except:
        return False

关键点:锁确保了检查-写入操作的原子性,避免了竞态条件,保证了数据的一致性。

posted @ 2025-11-03 20:37  ylifs  阅读(15)  评论(0)    收藏  举报