Eu só queria ressaltar que o gnu uniq
parece terrivelmente lento, mesmo em uma lista classificada.
Eu apenas tentei obter uma lista de prefixos de diretório de uma lista de nomes de arquivos classificados:
$ pv all_files | cut -d '/' -f 1,2,3,4 | uniq > all_prefixes
36.7GiB 0:07:41 [81.4MiB/s]
$ pv all_files | cut -d '/' -f 1,2,3,4 | sort -u > all_prefixes2
36.7GiB 0:03:14 [ 193MiB/s]
$ pv all_files | cut -d '/' -f 1,2,3,4 | awk '!x[$0]++' > all_prefixes3
36.7GiB 0:02:18 [ 270MiB/s]
sort -u parece duas vezes mais rápido que o uniq, e isso ocorre com a leitura de stdin e escrita para stdout, então não vejo ainda nenhuma paralelização. Eu não tenho idéia por que o uniq deve ser muito mais lento que a classificação, já que não precisa classificar a lista ...
A saída desse comando é muito pequena (existem muitas duplicatas), apenas 264kb e a classificação termina instantaneamente após a conclusão do PV.
As mesmas velocidades permanecem se você inverter a ordem dos comandos, meu fluxo é limitado pelo tempo da CPU aqui, não pelo acesso ao disco e caches (eu tenho apenas 8 GB de RAM e minha troca não é usada)
Estou executando isso em uma máquina fedora 31 com gnu coreutils sort e uniq e gnu awk; locale está definido como en_US.UTF-8
ATUALIZAÇÃO , como isso me intrigou bastante, fiz mais alguns testes, vamos cortar a parte do caminho e garantir que o arquivo esteja bem classificado
cat all_files | cut -d '/' -f 1,2,3,4 | sort -T . > test
Isso leva 8,4 minutos. teste agora é 7,9 GB grande
vamos executar essas ferramentas no arquivo em vez de em um pipe, isso permitirá que essas ferramentas otimizem um pouco mais, como a classificação será multithread. e também de um ssd mais rápido.
Você pode não perceber que essa classificação também está consumindo muita memória, pois faz truques inteligentes com arquivos temporários em / tmp, que podem ser tmpfs e estarão em sua memória RAM (tente classificar um arquivo maior que / tmp, você irá correr para o espaço problemas, é por isso que eu preciso da bandeira -T. no comando acima)
$ time sort -u test > /dev/null
339.24user 3.54system 1:28.87elapsed 385%CPU (0avgtext+0avgdata 2365856maxresident)k
9555544inputs+0outputs (0major+591298minor)pagefaults 0swaps
$ time awk '!x[$0]++' test > /dev/null
51.15user 1.55system 0:52.94elapsed 99%CPU (0avgtext+0avgdata 10976maxresident)k
0inputs+0outputs (0major+1923minor)pagefaults 0swaps
$ time uniq test > /dev/null
421.89user 2.76system 7:06.63elapsed 99%CPU (0avgtext+0avgdata 1980maxresident)k
52712inputs+0outputs (0major+79minor)pagefaults 0swaps
Parece que sua solução awk é a mais rápida dessas 3 e, na verdade, usa menos memória
update2
e agora com uma localidade mais simples
$ export LC_ALL=c
$ time sort -u test > /dev/null 1.2m ? Tue Apr 21 17:09:22 2020
119.18user 3.64system 0:38.24elapsed 321%CPU (0avgtext+0avgdata 2013472maxresident)k
$ time awk '!x[$0]++' test > /dev/null 1161ms ? Tue Apr 21 17:07:31 2020
67.23user 2.50system 1:10.16elapsed 99%CPU (0avgtext+0avgdata 10480maxresident)k
7187520inputs+0outputs (0major+1912minor)pagefaults 0swaps
$ time uniq test > /dev/null
22.05user 2.02system 0:24.24elapsed 99%CPU (0avgtext+0avgdata 1488maxresident)k
2959648inputs+0outputs (1major+72minor)pagefaults 0swaps
Desta vez, o uniq vence a corrida ... como Stéphane Chazelas sugere nos comentários, definir seu local para C torna a classificação e o uniq muito mais rápidos!
time
?