MST

星途 面试题库

面试题:Python信号量与锁在复杂并发场景中的优化策略

假设你正在开发一个高并发的网络爬虫程序,需要限制同时访问网站的线程数量以避免被封禁,并且不同类型的页面解析任务之间存在资源竞争。请说明如何综合运用信号量与锁来优化这个程序的性能和稳定性,同时避免死锁,并给出关键代码片段。
12.5万 热度难度
编程语言Python

知识考点

AI 面试

面试题答案

一键面试
  1. 信号量(Semaphore):用于限制同时访问网站的线程数量。信号量可以看作是一个计数器,允许一定数量的线程同时进入临界区。
  2. 锁(Lock):用于解决不同类型页面解析任务之间的资源竞争问题。锁可以保证同一时间只有一个线程访问共享资源。
  3. 避免死锁
    • 按顺序获取锁:所有线程按照相同的顺序获取锁,避免循环依赖。
    • 使用超时机制:在获取锁时设置超时时间,如果在规定时间内无法获取锁,则放弃并释放已获取的锁。

关键代码片段(Python 示例)

import threading
import requests
from bs4 import BeautifulSoup

# 信号量,限制同时访问网站的线程数量
semaphore = threading.Semaphore(5)

# 不同类型页面解析任务的锁
lock_type1 = threading.Lock()
lock_type2 = threading.Lock()

def crawl(url, page_type):
    with semaphore:
        try:
            response = requests.get(url)
            if response.status_code == 200:
                if page_type == 'type1':
                    with lock_type1:
                        soup = BeautifulSoup(response.content, 'html.parser')
                        # 进行 type1 页面的解析任务
                        pass
                elif page_type == 'type2':
                    with lock_type2:
                        soup = BeautifulSoup(response.content, 'html.parser')
                        # 进行 type2 页面的解析任务
                        pass
        except Exception as e:
            print(f"Error crawling {url}: {e}")

# 创建并启动线程
urls = ['http://example.com', 'http://example2.com']
page_types = ['type1', 'type2']

threads = []
for url, page_type in zip(urls, page_types):
    t = threading.Thread(target=crawl, args=(url, page_type))
    threads.append(t)
    t.start()

for t in threads:
    t.join()

在上述代码中:

  • semaphore 限制了同时访问网站的线程数量为 5。
  • lock_type1lock_type2 分别用于保护 type1type2 页面解析任务的共享资源,避免资源竞争。
  • 通过 with 语句,确保在任务完成后自动释放信号量和锁,提高代码的安全性和可读性。