如何加速大文件的写入过程?

3
以下代码从一个大的文本文件中随机获取几行,并将原始大文件分成两部分。在最后的“for”循环中,将文本写入两个文件非常缓慢。是否可以使用multiprocessing模块使其更快?我对此还不熟悉。
with open('bigfile.txt', 'r') as f, \
    open('split1.txt', 'w') as a, \
    open('split2.txt', 'w') as b:

    all_lines = f.readlines()
    size = len(all_lines)
    print("total size: ", str(size))
    line_numbers = []

    for i in range(size):
        line_numbers.append(i)

    random_sample_line_numbers = shuffle_list(line_numbers, 30000)
    print('Random sample size: ', str(len(random_sample_line_numbers)))
    for i in range(size):
        print(i)
        if i in random_sample_line_numbers:
            b.write(all_lines[i])
        else:
            a.write(all_lines[i])

    print("Randomize done!")

编辑:

def shuffle_list(l, n):
    if n>=len(l):
        raise ValueError("Invalid randomized number. Out of list index boundary")
    shuffle(l)
    return l[:n]

这需要数小时才能将大约2000万行的文件分割。该文件的总大小为2.6G。


你使用的是哪个Python版本? - smac89
你是自己编写了 shuffle_list,还是它是内置的?如果你自己编写了,能否描述一下它的功能或者在这里贴出代码呢? - smac89
1
文件有多大?请提供总大小,而不是行数。 - smac89
1
简短回答:是的,可以大大加快速度。在b中确切地拥有30K条记录很重要吗?或者近似数量也可以工作? - Marat
1
如果您将该变量设置为 set 而不是 list,那么 random_sample_line_numbers 中的 i 测试速度会更快。但是我不知道该测试占用了您总时间的多少。 - jasonharper
显示剩余4条评论
1个回答

0

没有必要将整个输入文件读入内存。你真正需要的只是知道行数。假设你已经知道了,称之为n。(如果需要,可以在文件的另一个传递中计算出来)。现在,当你阅读输入时,你可以根据已选择的随机行数的数量选择要写入哪个文件。

import random

with open('bigfile.txt', 'r') as f, \
    open('split1.txt', 'w') as a, \
    open('split2.txt', 'w') as b:

    # Compute number of lines, if necessary
    for size, _ in enumerate(f, start=1):
        pass

    f.seek(0)  # Start over

    for line in f:
        out = random.choices([a, b], [n, size - n])
        if out is a:
            n -= 1
        size -= 1
        out.write(line)

你可以证明这样做给予每行相同的被文件 a 选中的概率。直观地讲,每次选择一行,选择后面一行的概率会减小,因为可用的“空位”变少了。同时,随着您阅读文件,概率会增加,因为剩下的选择变得越来越少。在极端情况下,当 n 达到0时,您将停止选择行,并且您将始终在 n == size 时选择一行。

如果您甚至有一个大致的估计值,可以使用它而不必完全读取整个文件来计算其确切大小,而不会偏离真正的均匀分布太多。


两个问题:选择不是完全随机的(概率取决于行号),如果不严格执行确切计数,则可以避免两次通行。 - Marat
第一个问题:这在数学上等同于均匀选择一组固定大小的线。早期的线被选中的概率比后来的线小,但这被后来的线被考虑的概率较小所平衡。我会在答案的结尾解决第二个问题。 - chepner
是的,我可以在离线状态下获取总行数。 - ling
这似乎也是一个适用于更大文件的绝佳解决方案! - ling
@chepner 我错了。我误读了条件,试图解决一个略微不同的问题。 - Marat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接