MST

星途 面试题库

面试题:Python高效并发写入单行数据到多个文件

假设有一个任务,需要将一系列单行数据(数据量较大,例如10000条)并发地写入到多个不同的文件中(文件数量也较多,例如100个)。请设计并实现一个Python方案,使用多线程或多进程模块,确保写入操作高效且线程/进程安全,同时要考虑文件命名规范(例如按顺序命名为file1.txt, file2.txt等)以及数据的合理分配。阐述你选择多线程还是多进程的原因,以及如何处理可能出现的资源竞争问题。
18.4万 热度难度
编程语言Python

知识考点

AI 面试

面试题答案

一键面试
import os
import concurrent.futures
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor


def write_to_file(data_chunk, file_num):
    file_name = f'file{file_num + 1}.txt'
    with open(file_name, 'w') as f:
        for line in data_chunk:
            f.write(line + '\n')


def distribute_data(data, num_files):
    chunk_size = len(data) // num_files
    data_chunks = [data[i * chunk_size: (i + 1) * chunk_size] for i in range(num_files)]
    # 处理余数
    if len(data) % num_files != 0:
        data_chunks[-1].extend(data[num_files * chunk_size:])
    return data_chunks


def parallel_write(data, num_files, use_processes=False):
    data_chunks = distribute_data(data, num_files)
    executor_type = ProcessPoolExecutor if use_processes else ThreadPoolExecutor
    with executor_type(max_workers=num_files) as executor:
        executor.map(write_to_file, data_chunks, range(num_files))


if __name__ == '__main__':
    # 生成模拟数据
    data = [f'data line {i}' for i in range(10000)]
    num_files = 100
    parallel_write(data, num_files, use_processes=True)


选择多进程的原因

  1. CPU 密集型任务:当写入大量数据时,磁盘 I/O 虽然是主要操作,但在多核心 CPU 环境下,多进程可以利用多核并行处理能力,提升整体效率。而多线程由于 GIL(全局解释器锁)的存在,在 Python 中无法真正利用多核优势进行并行计算,对于 I/O 密集型任务多线程可能有一定优势,但在此场景下,由于数据量和文件数量较大,多进程的并行处理优势更明显。

  2. 资源隔离:每个进程都有自己独立的地址空间,这意味着不同进程之间不会相互干扰,能有效避免因共享资源而导致的复杂同步问题,例如全局变量的修改冲突等。

处理资源竞争问题

  1. 文件写入:使用 with open 语句来确保文件操作的原子性。在 write_to_file 函数中,with open(file_name, 'w') as f 会在操作完成后自动关闭文件,避免了多个进程同时写入同一文件时可能出现的数据错乱。同时,由于每个进程处理不同的数据块并写入不同的文件,不存在对同一文件的资源竞争。

  2. 数据分配:通过 distribute_data 函数将数据合理分配到不同的数据块中,每个进程负责处理一个数据块并写入对应的文件,保证了数据分配的合理性且避免了数据处理上的竞争。

如果选择多线程,同样使用 with open 语句保证文件写入安全,但需要额外注意 GIL 对效率的影响,并且可能需要使用 Lock 等同步机制来确保线程安全,例如对共享资源(如全局计数器等)的访问。但在本场景下,多线程在效率上不如多进程。