diff consumindo grande quantidade de memória e cpu

5

Eu tenho dois arquivos, all.txt (525,953,272 registros) e subset.txt (525,298,281 registros). Cada registro é nada mais que um inteiro ASCII de 17 dígitos. Ambos os arquivos foram classificados e os registros duplicados em cada arquivo foram removidos. Todos os valores em subset.txt também existem em all.txt . Desejo encontrar os registros em all.txt que não estão em subset.txt .

Estou tentando executar um diff entre esses dois arquivos, pensando que ele gravará as linhas que estão em all.txt , mas não em subset.txt . A máquina tem 64GB de memória. O diff está em execução há meia hora e atualmente adquiriu cerca de 75% da memória.

Alguém pode especular sobre o que pode estar acontecendo e se há argumentos para diff que podem ajudar? Isso não é o que o diff deveria fazer, e há uma abordagem diferente que eu deveria usar?

    
por Chap 24.01.2016 / 01:31

2 respostas

2

Can anyone speculate on what might be going on, and whether there are arguments to diff that might help? Is this just not what diff was meant to do, and is there a different approach I should use?

Não é isso que diff pretendia fazer; quando as entradas foram classificadas (como você tem), a ferramenta para o trabalho é comm .

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

As opções para comm são um pouco incomuns, pois elas transformam saída off . A coluna 1 tem linhas exclusivas do arquivo 1; a coluna 2 possui linhas exclusivas do arquivo 2; e coluna 3 tem linhas que são "comm" para ambos. Ao usar as opções -13 , estamos pedindo que a Comm nos mostre as linhas que estão apenas em "all.txt".

    
por 24.01.2016 / 15:12
0

diff pode não ser a ferramenta mais adequada para isso. Eu tentaria escrever um script simples que faz especificamente o que você quer.

Tudo na memória

Esta é uma solução muito simples e genérica. Ele carrega os dois arquivos em estruturas de memória minimalista, subtrai os registros de subset.txt dos registros de all.txt e grava o restante.

#!/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)

Salve em um arquivo como create_diff.py e, em seguida, chmod +x create_diff.py e execute-o no diretório onde estão seus dois arquivos.

Apenas subconjunto na memória

Se você precisar otimizar ainda mais para um consumo de memória menor, também seria possível fazer isso sem carregar os arquivos inteiros na memória, especialmente all.txt não precisa ser carregado completamente na memória, mas pode ser iterado apenas uma vez .

#!/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)

Baseado em E / S

Essa deve ser a variante mais lenta, porque depende muito de E / S, mas ela tem pouca memória, porque não exige que os arquivos inteiros sejam carregados na memória. Ele funciona, não importa se seus arquivos estão classificados / unidos ou não.

#!/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()

Somente para arquivos classificados sem duplicatas < - recomendados no seu caso

Se tiver certeza de que seus arquivos estão ordenados e não contêm duplicatas, essa deve ser a melhor solução. Ambos os arquivos são lidos apenas uma vez e não precisam ser completamente carregados na memória.

#!/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()
    
por 24.01.2016 / 11:30