【Python 实战】100 TB 大文件自然数排序解决方案详解(附完整代码)

📌 一、问题背景

  • 输入数据: 一个大小为 100TB 的文本文件,每行一个自然数。
  • 可用资源: 内存限制为 16GB
  • 目标: 对这 100TB 的数据进行升序排序并输出到文件。

由于数据量远大于内存容量,无法一次性加载全部数据进行排序,因此需要采用分治 + 外排序的方法来解决。


🧩 二、解决方案概述

整个流程分为四个核心步骤:

  1. 查找最大值: 遍历原始文件找到最大数值,用于后续合理划分区间。
  2. 分片(Partitioning): 按照数值范围将大文件拆分成多个小文件。
  3. 排序(Internal Sorting): 将每个小文件加载进内存排序后写入磁盘。
  4. 多路归并(K-way Merge): 使用最小堆算法合并所有已排序的小文件,生成最终有序结果。

🛠️ 三、具体实现步骤详解

✅ 步骤 1:查找最大值

def find_max_number(file_path):
    max_num = 0
    with open(file_path, 'r') as f:
        for line in f:
            num = int(line.strip())
            if num > max_num:
                max_num = num
    return max_num

🔍 说明:

这一步是为了动态设置数值区间的大小,确保分区均匀,避免出现某些分区过大或为空的情况。


✅ 步骤 2:按数值区间分片

def partition_file(max_num):
    range_size = max_num // NUM_PARTITIONS + 1
    partition_files = [
        open(os.path.join(PARTITION_DIR, f'partition_{i}.txt'), 'w')
        for i in range(NUM_PARTITIONS)
    ]

    with open(INPUT_FILE, 'r') as f:
        for line in f:
            num = int(line.strip())
            idx = num // range_size
            if idx >= NUM_PARTITIONS:
                idx = NUM_PARTITIONS - 1
            partition_files[idx].write(line)

    for fp in partition_files:
        fp.close()

🔍 说明:

使用 num // range_size 计算该数字属于哪个分区,从而将原始数据分散到多个文件中,便于后续排序。


✅ 步骤 3:内部排序每个小文件

def sort_partitions():
    for i in range(NUM_PARTITIONS):
        input_path = os.path.join(PARTITION_DIR, f'partition_{i}.txt')
        output_path = os.path.join(PARTITION_DIR, f'sorted_partition_{i}.txt')

        with open(input_path, 'r') as f:
            nums = list(map(int, f.readlines()))
        nums.sort()

        with open(output_path, 'w') as f:
            for num in nums:
                f.write(str(num) + '\n')

🔍 说明:

每个小文件的数据量控制在 1GB 左右,可以轻松加载进内存进行排序。


✅ 步骤 4:多路归并排序(K-way Merge)

def merge_sorted_partitions():
    heap = []
    pointers = []

    for i in range(NUM_PARTITIONS):
        path = os.path.join(PARTITION_DIR, f'sorted_partition_{i}.txt')
        fp = open(path, 'r')
        line = fp.readline()
        if line:
            heapq.heappush(heap, (int(line.strip()), i))
        pointers.append(fp)

    with open(OUTPUT_FILE, 'w') as out_file:
        while heap:
            val, idx = heapq.heappop(heap)
            out_file.write(str(val) + '\n')

            next_line = pointers[idx].readline()
            if next_line:
                heapq.heappush(heap, (int(next_line.strip()), idx))

    for fp in pointers:
        fp.close()

🔍 说明:

使用 最小堆 来高效地从多个有序文件中取出当前最小值,逐步构建最终有序序列。这是大数据归并的经典做法。


📈 四、时间复杂度与性能分析

步骤时间复杂度说明
查找最大值O(N)遍历一次文件
分片O(N)每个数字只处理一次
排序各分片O(n log n) × K每个分片排序
多路归并O(N log K)使用堆结构高效归并

整体效率高,适合处理超大规模数据。


🧪 五、测试脚本:生成 1GB 测试数据

为了验证程序是否正常工作,我们可以先生成一个 1GB 的测试文件:

import random

TARGET_SIZE_BYTES = 1 * 1024 * 1024 * 1024  # 1GB
CHUNK_SIZE = 100000

with open('input.txt', 'w') as f:
    total = 0
    while total < TARGET_SIZE_BYTES:
        data = '\n'.join(str(random.randint(0, 10**9)) for _ in range(CHUNK_SIZE)) + '\n'
        f.write(data)
        total += len(data.encode())
        print(f"\r已写入: {total // (1024 * 1024)} MB", end='')

📦 六、总结

通过这篇文章,我们了解了如何使用 Python 对一个 1TB 的自然数文件 进行排序,主要涉及以下关键技术点:

  • 外排序思想(External Sort)
  • 分片(Partitioning)
  • 内存排序
  • 多路归并(K-way Merge)
  • 最小堆(优先队列)

这套方案不仅适用于 1TB 文件排序,也可以扩展到更大的数据集和分布式系统中。


📚 七、参考资料 & 延伸阅读

  • External sorting - Wikipedia
  • Python 官方文档:heapq / mmap / multiprocessing
  • CSDN 热门博文推荐:《MapReduce 实现大数据排序》《基数排序原理详解》

💬 八、结语

如果你觉得这篇文章对你有帮助,欢迎点赞、收藏、评论支持一下作者!

如需获取完整代码打包版本、带进度条优化版、日志记录功能、甚至封装成命令行工具,请在评论区留言,我可以继续为你完善!


GitHub / Gitee 示例项目地址(可选):
👉 https://github.com/phil-zhan/external-sort


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值