расходует огромное количество памяти и процессора

5

У меня есть два файла, all.txt (525 953 272 записей) и subset.txt (525 298 281 записей). Каждая запись является ничем иным, как 17-значным целым числом ASCII. Оба файла были отсортированы, и дубликаты записей в каждом файле были удалены. Каждое значение в subset.txt также существует в all.txt . Я хочу найти записи в all.txt , которых нет в subset.txt .

Я пытаюсь запустить diffмежду этими двумя файлами, думая, что он запишет строки, которые находятся в all.txt, но не в subset.txt . Машина имеет 64 ГБ памяти. Он diffработал в течение получаса и в настоящее время получил около 75% памяти.

Может ли кто-нибудь порассуждать о том, что может происходить, и могут ли diffпомочь такие аргументы ? Разве это не то, что diffдолжно было быть сделано, и есть ли другой подход, который я должен использовать?

Глава
источник
1
525953272 × 17 bytes × 2 ≈ 16 GiBи 64 × 0.75 / 16 = 3. В качестве отправной точки. Не исключено, что утилита diff сможет использовать 2x. Что diff? Нечто подобноеdiff --version
user367890
1
Вы думали написать простую программу для этого? Учтите, что каждый файл отсортирован. Вы будете продвигаться линейно на обоих файлах с разной скоростью. (Черпайте вдохновение у mergesort, если вы не понимаете, о чем я)
Василий Старынкевич
5
Смотрите такжеcomm
Джефф Шаллер
@ user367890 $ diff - версия diff (GNU diffutils) 2.8.1 Copyright (C) 2002 Free Software Foundation, Inc.
Глава
@JeffSchaller - кажется, что comm делает именно то, что мне нужно. Дайте это как ответ, и я приму это. Спасибо.
Глава

Ответы:

2

Кто-нибудь может порассуждать о том, что может происходить, и есть ли аргументы для сравнения, которые могут помочь? Разве это не то, что должен был делать diff, и есть ли другой подход, который я должен использовать?

Это не то, что diffдолжно было быть сделано; когда входные данные были отсортированы (как у вас есть), инструмент для работы comm.

$ seq 10 15 > subset.txt
$ seq 10 20 > all.txt
$ comm -13 subset.txt all.txt
16
17
18
19
20

В опции дляcomm немного необычна тем , что они поворачиваются от выхода. Столбец 1 содержит строки, которые являются уникальными для файла 1; столбец 2 содержит строки, которые являются уникальными для файла 2; и в столбце 3 есть строки, которые являются «comm» для обоих. Используя опции, -13мы просим comm показать нам строки, которые есть только в «all.txt».

Джефф Шаллер
источник
0

diffможет быть не самый подходящий инструмент для этого. Я бы попытался написать простой сценарий, который делает именно то, что вы хотите.

Все в памяти

Это очень простое и общее решение. Он загружает два файла в минималистические структуры памяти, вычитает записи subset.txtиз записей all.txtи записывает остаток.

#!/usr/bin/env python

with open('diff.txt', 'w') as diff:

    for record in set(open('all.txt', 'r')) - set(open('subset.txt', 'r')):
        diff.write(record)

Сохраните это в файл, как create_diff.py, затем chmod +x create_diff.pyзапустите его в каталоге, где находятся два ваших файла.

Только подмножество в памяти

Если вам потребуется дальнейшая оптимизация для уменьшения занимаемой памяти, это также возможно сделать без загрузки всех файлов в память, особенно all.txtне нужно загружать их в память полностью, а можно просто повторить один раз.

#!/usr/bin/env python

subset_txt = open('subset.txt', 'r')
subset = subset_txt.readlines()
subset_txt.close()

with open('diff.txt', 'w') as diff_txt:
    with open('all.txt', 'r') as all_txt:
        for line in all_txt:
            if line not in subset:
                diff_txt.write(line)

На основе ввода / вывода

Это должен быть самый медленный вариант, потому что он сильно зависит от ввода-вывода, но он занимает мало памяти, поскольку не требует загрузки всех файлов в память. Это работает независимо от того, отсортированы ли ваши файлы или нет, или нет.

#!/usr/bin/env python

diff_txt = open('diff.txt', 'w')

with open('all.txt', 'r') as all_txt:
    with open('subset.txt', 'r') as subset_txt:
        for all_line in all_txt:
            found = False

            for sub_line in subset_txt:
                if all_line == sub_line:
                    found = True
                    break

            if found is False:
                diff_txt.write(all_line)
                subset_txt.seek(0)

diff_txt.close()

Только для отсортированных файлов без дубликатов <- рекомендуется в вашем случае

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

#!/usr/bin/env python

diff_txt = open('diff.txt', 'w')

with open('all.txt', 'r') as all_txt:
    with open('subset.txt', 'r') as subset_txt:
        subset_line = subset_txt.readline()

        for all_line in all_txt:
            if all_line == subset_line:
                subset_line = subset_txt.readline()
            else:
                diff_txt.write(all_line)

diff_txt.close()
переигровка
источник