MST

星途 面试题库

面试题:Python 列表元素访问边界问题之性能优化与异常处理策略

在一个高并发的Python应用场景中,有多个线程会频繁访问一个共享的大列表(假设列表元素数量在百万级别)。由于不同线程的操作可能导致列表元素访问的边界问题,现要求你设计一个机制,既要保证对列表元素访问边界的有效检查,又要尽可能减少性能损耗(例如锁带来的开销)。请描述你的整体设计思路,并给出关键代码片段及相应解释。
28.7万 热度难度
编程语言Python

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 使用队列替代直接访问列表:利用queue.Queue来管理对共享数据的访问。Queue本身是线程安全的,内部实现了锁机制来保证数据一致性,减少手动加锁解锁的开销。
  2. 边界检查封装:将对列表元素的访问逻辑封装在函数中,在函数内部进行边界检查,确保每次访问都是安全的。
  3. 生产者 - 消费者模型:使用生产者 - 消费者模型,线程作为生产者将任务(如对列表的访问请求)放入队列,而一个或多个消费者线程从队列中取出任务并执行,这样可以解耦线程对共享列表的直接操作。

关键代码片段及解释

import queue
import threading


# 共享大列表
large_list = list(range(1000000))


# 任务队列
task_queue = queue.Queue()


# 边界检查及列表访问函数
def access_list(index):
    if 0 <= index < len(large_list):
        return large_list[index]
    else:
        raise IndexError("Index out of range")


# 消费者线程函数
def consumer():
    while True:
        index = task_queue.get()
        try:
            result = access_list(index)
            print(f"Accessed element: {result}")
        except IndexError as e:
            print(f"Error: {e}")
        task_queue.task_done()


# 创建并启动消费者线程
consumer_thread = threading.Thread(target=consumer)
consumer_thread.daemon = True  # 设置为守护线程,主线程结束时自动退出
consumer_thread.start()


# 模拟生产者(其他线程)向队列中添加任务
def producer():
    for i in range(10):  # 模拟10次访问请求
        task_queue.put(i)


# 创建并启动生产者线程
producer_thread = threading.Thread(target=producer)
producer_thread.start()


# 等待所有任务完成
task_queue.join()
  1. large_list:定义共享的大列表。
  2. task_queue:创建一个任务队列,用于线程间传递对列表访问的请求。
  3. access_list函数:封装了对列表的访问逻辑,并进行边界检查。如果索引在合法范围内,返回列表元素;否则抛出IndexError
  4. consumer函数:消费者线程的执行函数,不断从任务队列中获取任务(列表索引),调用access_list函数进行访问,并处理可能出现的索引错误。处理完任务后,调用task_queue.task_done()通知队列任务已完成。
  5. producer函数:模拟生产者线程,向任务队列中添加任务(这里简单地添加索引值)。
  6. 线程启动与等待:创建并启动消费者线程和生产者线程,最后通过task_queue.join()等待所有任务完成。消费者线程设置为守护线程,主线程结束时,消费者线程也会自动结束。