Pesquisa e Ordenação - Aula 10 - Métodos de Ordenação (Distribuição - Heap sort)
Processamento Coseqüencial e ordenação de arquivos grandes
description
Transcript of Processamento Coseqüencial e ordenação de arquivos grandes
Processamento Coseqüencial e ordenação de arquivos grandes
Ordenação Externa
Operações Coseqüenciais
• Envolvem o processamento coordenado (simultâneo) de duas ou mais listas de entrada seqüenciais, de modo a produzir uma única lista como saída
• Exemplo: merging (intercalação) ou matching (intersecção) de duas ou mais listas mantidas em arquivo
Modelo para implementaçãode processos coseqüenciais
Lista 1
• Adams• Carter• Chin• Davis• Foster• Garwich• Rosewald• Turner
Lista 2
• Adams• Anderson• Andrews• Bech• Rosewald• Schmidt• Thayer• Walker• Willis
Modelo para implementaçãode processos coseqüenciais
• Algoritmo de intercalação– lê um nome de cada lista, e compara– se ambos são iguais, copia o nome para a saída e
avança para o próximo nome da lista em cada arquivo
– se o nome da Lista1 é menor, ele é copiado para a saída, e avança na Lista1
– se o nome da Lista1 é maior, copia o nome da Lista2 para a saída e avança na Lista2
Programa: Merge (versao 1)Intercala2Listas(lista1,lista2, lsaida, lsaida) { // As listas de entrada são objetos organizados em um vetor iniciaLista(1, Lista1); // inicia lista1 ao primeiro elemento do vetor de lista iniciaLista(2, lista2); iniciaSaida(lsaida); // inicia a lista de saida maisitens1 = proximoItemList(1); // retorna true se ainda existe um elemento valido na lista maisitens2 = proximoItemList(2); enquanto (maisitens1 ou maisitens2) { if (Item(1) < Item(2)) { ProcesssaItem(1); maisitens1 = proximoItemList(1); } else if (Item(1) = Item(2)) { ProcesssaItem(1); maisitens1 = proximoItemList(1); maisitens2 = proximoItemList(2); } else { // Item(1) > Item (2) ProcesssaItem(2); maisitens2 = proximoItemList(2); } } FinishUp(); // fecha os arquivos...}
Programa: Merge (versão 2) call initialize()
call input() to get NAME_1 from LIST_1 and NAME_2 from LIST_2while(MORE_NAMES_EXIST)if (NAME_1 < NAME_2)
write NAME_1 to OUT_FILEcall input() to get NAME_1 from LIST_1
else if (NAME_1 > NAME_2) write NAME_2 to OUT_FILE call input() to get NAME_2 from LIST_2
else /* match – names are the same */write NAME_1 to OUT_FILEcall input to get NAME_1 from LIST_1call input to get NAME_2 from LIST_2
finish_up()
Procedure INPUT (versão 2)
• Argumentos de entrada– INP_FILE: descritor do arquivo de entrada (LIST_1 ou
LIST_2)– PREVIOUS_NAME: nome lido da lista no passo
anterior– OTHER_LIST_NAME: último nome lido da outra lista
• Argumentos de saída– NAME – nome lido– MORE_NAMES_EXIST - flag para indicar a parada
Procedure INPUT (versão 2)
read next NAME from INP_FILEIf (EOF) and (OTHER_LIST_NAME == HIGH_VALUE)
MORE_NAME_EXIST := FALSE /* fim das duas listaselse if (EOF)
NAME:=HIGH_VALUE /* essa lista acabouelse if (NAME <= PREVIOUS_NAME) /* erro seqüencia
Msg. de erro, aborta processamentoendifPREVIOUS_NAME:=NAME
Ordenação por Intercalação deArquivos em Disco
• 2-Way Mergesort, ou intercalação em duas vias, em disco
• Ao invés de considerar os registros individualmente, podemos considerar blocos de registros ordenados (corridas, ou runs), para minimizar os seeks…
• Método envolve 2 fases: geração das corridas, e intercalação
2-Way Mergesort
• Fase 1: Geração das Corridas– segmentos do arquivo (corridas) são ordenados
em memória RAM, usando algum método eficiente de ordenação interna (p.ex., Quicksort), e gravados em disco
– corridas vão sendo gravadas a medida em que são geradas
2-Way Mergesort
• Fase 2: Intercalação– As corridas gerados na fase anterior são
intercaladas, duas a duas, formando corridas maiores que são gravadas em disco
– O processo continua até que uma única corrida seja obtida, que consiste de todo o arquivo ordenado
Ordenação “2-Way” : Requer 3 Buffers
• Passo 1: Ler uma página, ordená-la, escrevê-la.– Somente um buffer
• Passos 2, 3, …, etc.:– Três buffers.
Buffers em memória principal
INPUT 1
INPUT 2
OUTPUT
DiscoDisco
Two-Way Merge Sort Externo• Em cada passo lê-se e
escreve-se cada página no arquivo. Custo =
• N páginas no arquivo => o número de passos
• Custo total:
• Problema: não maximiza o
uso do buffer, gerando um grande nro de passos.
log2 1N
2 12N Nlog
Input file
1-page runs
2-page runs
4-page runs
8-page runs
PASSO 0
PASSO 1
PASS 2
PASS 3
9
3,4 6,2 9,4 8,7 5,6 3,1 2
3,4 5,62,6 4,9 7,8 1,3 2
2,34,6
4,7
8,91,35,6 2
2,3
4,46,7
8,9
1,23,56
1,22,3
3,4
4,56,6
7,8
N2
Intercalação em k-vias
• Não há motivo para restringir o número de entradas na intercalação a 2
• Podemos generalizar o processo para intercalar k corridas simultaneamente
• k-Way MergeSort
Intercalação em k-vias
• Esta solução– pode ordenar arquivos realmente grandes– geração das corridas envolve apenas acesso
seqüencial aos arquivos– a leitura das corridas e a escrita final também só
envolve acesso seqüencial– aplicável tb. a arquivos mantidos em fita, já que
E/S é seqüencial– Usar o buffer disponível para reduzir o número de
passos.
Intercalação em k-vias
• B páginas no buffer, e arquivo de N páginas:– Passo 0: gerar runs com B páginas cada. – Passo 1,2, …, etc.: (B-1) merge.
N B/
B Main memory buffers
INPUT 1
INPUT B-1
OUTPUT
DiskDisk
INPUT 2
. . . . . .
. . .
Mais que 3 buffers . Como utilizá-los?
Custo do K way merge sort externo• Número de passos:• Custo = 2N * (# de passos)• Ex. com 5 páginas de buffer p/ ordenar
arquivo com 108 páginas:– Passo 0: = 22 runs ordenadas de 5 págs.
cada (última run tem somente 3 páginas) – Passo 1: = 6 runs ordenadas de 20 págs.
cada (última run tem somente 8 páginas)– Pass 2: 2 runs, (80 págs e 28 págs.)– Pass 3: arquivo ordenado de 108 páginas
1 1 log /B N B
108 5/
22 4/
Número de passos.
N B=3 B=5 B=9 B=17 B=129 B=257100 7 4 3 2 1 11,000 10 5 4 3 2 210,000 13 7 5 4 2 2100,000 17 9 6 5 3 31,000,000 20 10 7 5 3 310,000,000 23 12 8 6 4 3100,000,000 26 14 9 7 4 41,000,000,000 30 15 10 8 5 4
Qual o custo (tempo) doMergeSort ?
• Supondo– Arquivo com 8 000 000 milhões de registros, 100 bytes cada registro
(800 MB) – Chave do registro: 10 bytes.– Memória disponível para operação= 10 MB– 10 MB RAM 100.000 registros– Arquivo armazenado em áreas contíguas do disco (extents), extents
alocados em mais de uma trilha, de tal modo que um único rotational delay é necessário para cada acesso
• Características do disco– tempo médio para seek: 18 ms– atraso rotacional: 8.3 ms– taxa de transferência: 1229 bytes/ms– tamanho da trilha: 200.000 bytes
Qual o custo (tempo) doMergeSort ?
• Quatro passos a serem considerados– leitura dos registros, do disco para a memória,
para criar as corridas– escrita das corridas ordenadas para o disco– leitura das corridas para intercalação– escrita do arquivo final em disco
Leitura dos registros e criaçãodas corridas
• Lê-se 10MB de cada vez, para produzir corridas de 10 MB
• Serão 80 leituras, para formar as 80 corridas iniciais
• O tempo de leitura de cada corrida inclui o tempo de acesso a cada bloco (seek + rotational delay) somado ao tempo necessário para transferir cada bloco
Leitura dos registros e criaçãodas corridas
• seek = 8ms, rot. delay = 3ms, total 11ms• Tempo total para a fase de ordenação:
80*(tempo de acesso a uma corrida) + tempo de transferência de 80MB
• Acesso: 80*(seek+rot.delay= 11ms) = 1s• Transferência: 800 MB a 14500 bytes/ms =
60s• Total: 61s
Escrita das corridas ordenadasno disco
• Idem à leitura!• Serão necessários outros 61s para se escrever
as 80 corridas (runs)
Leitura das corridas do disco paraa memória (para intercalação)
• Tem-se 10MB de MEMÓRIA para armazenar 80 buffers de entrada• Dividi-se 10MB em 80 partes para bufferizar 80 corridas– portanto, cada buffer armazena 1/80 de uma corrida
(125.000 bytes). Logo, cada corrida deve ser acessada 80 vezes para ser lida por completo
• 80 acessos para cada corrida X 80 corridas – 6.400 seeks
• considerando acesso = seek + rot. Delay – 11ms X 6.400 = 70s
• Tempo para transferir 800 MB = 60s
Escrita do arquivo final em disco
• Precisamos saber o tamanho dos buffers de saída. Nos passos 1 e 2, a MEMÓRIA funcionou como buffer, mas agora a MEMÓRIA está armazenando os dados a serem intercalados
• Para simplificar, assumimos que é possível alocar 2 buffers de 200.000 bytes para escrita– dois para permitir double buffering, 200.000
porque é o tamanho da trilha no nosso disco hipotético
Escrita do arquivo final em disco
• Com buffers de 200.000 bytes, precisaremos de 800.000.000 bytes / 20.000 bytes por seek = 4.000 seeks
• Como tempo de seek+rot.delay = 11ms por seek, 4.000 seeks usam 4.000 X 11, e o total de 44s.
• Tempo de transferência é 60s
Tempo total
• leitura dos registros para a memória para a criação de corridas: 61s (seeks = 800)
• escrita das corridas ordenadas para o disco: 61s (seeks = 800)• leitura das corridas para intercalação: 70 + 60 =
130 s (seeks = 6400)• escrita do arquivo final em disco: 44 + 60 =
104 s (seeks = 4000)• Tempo total do Mergesort = 356 s (seeks = 10560)
Comparação
• Quanto tempo levaria um método que não usa intercalação?
– Se for necessário um seek separado para cada registro, i.e, 8.000.000 seeks a 11ms cada, o resultado seria um tempo total (só para seek) = 88.000s = 24 horas, 26 minutos e 40s !
Ordenação de um arquivo com80.000.000 de registros
• Análise - arquivo de 8000 MB– Na fase de ordenação não é possível melhorar I/O– Fase de merge
• Passo de leitura: o maior responsável • Passo de escrita: não é influenciado pelo modo da organização das
runs.
• O arquivo aumenta, mas a memória não!– Em vez de 80 corridas iniciais, teremos 800– Portanto, seria necessário uma intercalação em 800-vias
no mesmo 10 MB de memória, o que implica em que a memória seja dividida em 800 buffers na fase de intercalação
Ordenação de um arquivo com80.000.000 de registros
• Cada buffer comporta 1/800 de uma corrida, e cada corrida é acessada 800 vezes
• 800 corridas X 800 seeks/corrida = 640.000 seeks no total
• O tempo total agora é superior a 2 horas e 24 minutos, aproximadamente 25 vezes maior do que o arquivo de 800 MB (que é 10 apenas vezes menor do que este)
Ordenação de um arquivo com80.000.000 de registros
• Definitivamente: necessário diminuir o tempo gasto obtendo dados na fase de intercalação
O custo de aumentar otamanho do arquivo
• A grande diferença de tempo na intercalação dos dois arquivos (de 800 e 8000 MB) é conseqüência da diferença nos tempos de acesso às corridas (seek e rotational delay)
• Em geral, para uma intercalação em K-vias de K corridas, em que cada corrida é do tamanho da MEMÓRIA disponível, o tamanho do buffers para cada uma das corridas é de: – (1/K) x tamanho da MEMÓRIA = (1/K) x tamanho de
cada corrida
Complexidade do Mergesort
• Como temos K corridas, a operação de intercalação requer K2 seeks
• Medido em termos de seeks, o Mergesort é O(K2)
• Como K é diretamente proporcional à N , o Mergesort é O(N2), em termos de seeks
Maneiras de reduzir essetempo
• usar mais hardware (disk drives, MEMÓRIA, canais de I/O)
• realizar a intercalação em mais de um passo, o que reduz a ordem de cada intercalação e aumenta o tamanho do buffer para cada corrida
• aumentar o tamanho das corridas iniciais• realizar I/O simultâneo à intercalação
Redução do número de seeks:Intercalação em Múltiplos Passos
(Multistep Merging)• ao invés de intercalar todas as corridas
simultaneamente, o grupo original é dividido em sub-grupos menores
• intercalação é feita para cada sub-grupo• para cada sub-grupo, um espaço maior é alocado para
cada corrida, portanto um número menor de seeks é necessário
• uma vez completadas todas as intercalações pequenas, o segundo passo completa a intercalação de todas as corridas
Intercalação em Múltiplos Passos• É claro que um número menor de seeks será feito no
primeiro passo. E no segundo?• O segundo passo exige não apenas seeking, mas
também transferências nas leituras/escritas. Será que as vantagens superam os custos?
• No exemplo do arquivo com 800 MB tínhamos 800 corridas com 10.000 registros cada. Para esse arquivo, a intercalação múltipla poderia ser realizada em dois passos:– primeiro, a intercalação de 25 conjuntos de 32 corridas
cada– depois, uma intercalação em 25-vias
Intercalação em Múltiplos Passos
• passo único visto anteriormente exige 640.000 seeks. Para a intercalação em 2 passos, temos, no passo 1:– Cada intercalação em 32-vias aloca buffers que
podem conter 1/32 de uma corrida. Então, serão realizados 32 X 32 = 1024 seeks
– Então, 25 vezes a intercalação em 32-vias exige 25 X 1024 = 25.600 seeks
– Cada corrida resultante tem 32 X 100.000 = 3.200.000 registros = 320 MB
Intercalação em Múltiplos Passos
• No passo 2, cada uma das 25 corridas de 32 MB pode alocar 1/25 do buffer– portanto, cada buffer aloca 4000 registros, ou
seja, 1/800 corrida. Então, esse passo exige 800 seeks por corrida, num total de 25 X 800 = 20.000 seeks
– Total de seeks nos dois passos: 25.600 + 20.000 = 45.600
E o tempo total de intercalação?
• Nesse caso, cada registro é transmitido 4 vezes, em vez de duas. Portanto, gastamos mais 1200s em tempo de transmissão
• Ainda, cada registro é escrito duas vezes: mais 40.000 seeks (assumindo 2 buffers de 200.000 bytes cada)
• Somando tudo isso, o tempo total de intercalação = 3782s ~ 1hora 3 min.
• A intercalação em 800 vias consumia 2h, 25m
Aumento do tamanho das corridas• Se pudéssemos alocar corridas com 20.000
registros, ao invés de 10.000 (limite imposto pelo tamanho da MEMÓRIA), teríamos uma intercalação em 400-vias, ao invés de 800
• Neste caso, seriam necessários 800 seeks por corrida, e o número total de seeks seria: 800 seeks/corrida X 400 corridas = 320.000 seeks.– Portanto, dobrar o tamanho das corridas reduz o
número de seeks pela metade• Como aumentar o tamanho das corridas iniciais
sem usar mais memória?
Replacement Selection• Idéia básica: selecionar na memória a menor chave,
escrever esse registro no buffer de saída, e usar seu lugar (replace it) para um novo registro (da lista de entrada). Os passos são:
• Leia um conjunto de registros e ordene-os utilizando heapsort, criando uma heap (heap primária)
• Ao invés de escrever, neste momento, a heap primária inteira ordenadamente e gerar uma corrida (como seria feito no heapsort normal), escreva apenas o registro com menor chave
Replacement Selection
3. Busque um novo registro no arquivo de entrada e compare sua chave com a chave que acabou de ser escrita
Se ela for maior, insira o registro normalmente na heap Se ela for menor que qualquer chave já escrita, insira o registro numa heap secundária• Repita o passo 3 enquanto existirem registros a
serem lidos. Quando a heap primária fica vazia, transforme a heap secundária em primária, e repita os passos 2 e 3
Replacement Selection +Intercalação em Múltiplos Passos
• Para melhorar a eficiência: o método utilizado para formar as corridas é menos relevante do que utilizar intercalações múltiplas!