Как ускорить процесс записи файла для большого файла? - PullRequest
3 голосов
/ 06 февраля 2020

Следующий код берет случайное количество строк из большого текстового файла и разбивает исходный большой файл на две части. В последнем 'for' l oop запись текста в два файла выполняется очень медленно. Есть ли способ сделать это намного быстрее, используя многопроцессорный модуль? Я новичок в этом.

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]

Это занимает несколько часов , чтобы разбить файл с около 20 миллионов строк. Общий размер файла 2.6G.

1 Ответ

0 голосов
/ 06 февраля 2020

Нет необходимости читать весь входной файл в память. Все, что вам действительно нужно, это знать количество строк. Давайте предположим, что вы уже знаете это, и назовите это 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.

Если у вас есть даже приблизительная оценка того, что size должно быть Вы, вероятно, можете использовать это вместо чтения всего файла, чтобы вычислить его точный размер, не слишком отклоняясь от истинного равномерного распределения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...