MST

星途 面试题库

面试题:Python多线程环境下优雅退出的资源清理

在一个Python多线程程序中,有多个线程在处理文件读取和写入操作。每个线程在启动时打开一个文件,在结束时需要关闭文件以避免资源泄露。请设计一个优雅退出线程的方案,确保所有线程在收到退出信号后,能正确关闭文件并安全退出,同时避免线程间的竞争条件。请详细阐述实现思路并给出关键代码示例。
38.0万 热度难度
编程语言Python

知识考点

AI 面试

面试题答案

一键面试

实现思路

  1. 信号处理:使用signal模块捕获系统退出信号(如SIGTERMSIGINT),设置信号处理函数。
  2. 共享标志:定义一个共享的标志变量,用于通知各个线程需要退出。线程在执行过程中,需要定期检查这个标志。
  3. 锁机制:为了避免线程间竞争条件,在对共享资源(如文件操作)进行访问时,使用锁(threading.Lock)来保证同一时间只有一个线程可以操作。
  4. 文件管理:每个线程在启动时打开文件,并将文件对象保存在线程本地数据中。在收到退出信号后,线程关闭文件。

关键代码示例

import threading
import signal
import time


# 共享退出标志
exit_flag = False
# 锁
file_lock = threading.Lock()


def worker(file_path):
    global exit_flag
    local_file = None
    try:
        # 打开文件
        with file_lock:
            local_file = open(file_path, 'a')
        while not exit_flag:
            # 模拟文件写入操作
            with file_lock:
                local_file.write('Some data\n')
                local_file.flush()
            time.sleep(1)
    except Exception as e:
        print(f"线程发生异常: {e}")
    finally:
        # 关闭文件
        if local_file:
            with file_lock:
                local_file.close()


def signal_handler(sig, frame):
    global exit_flag
    print('收到退出信号,正在安全退出...')
    exit_flag = True


# 注册信号处理函数
signal.signal(signal.SIGTERM, signal_handler)
signal.signal(signal.SIGINT, signal_handler)


# 创建并启动线程
threads = []
file_paths = ['file1.txt', 'file2.txt', 'file3.txt']
for file_path in file_paths:
    t = threading.Thread(target=worker, args=(file_path,))
    t.start()
    threads.append(t)


# 等待所有线程结束
for t in threads:
    t.join()

print('所有线程已安全退出')

代码解释

  1. 共享标志exit_flag用于通知线程需要退出。
  2. 锁机制file_lock确保文件操作的线程安全。
  3. worker函数:每个线程执行的函数,打开文件并在未收到退出信号时进行写入操作,在退出时关闭文件。
  4. signal_handler函数:信号处理函数,设置exit_flagTrue,通知线程退出。
  5. 信号注册:使用signal.signal注册SIGTERMSIGINT信号的处理函数。
  6. 线程创建与启动:创建多个线程并启动,每个线程处理不同的文件。
  7. 线程等待:主线程使用join方法等待所有线程结束。