Estratégias de E / S para problemas computacionais com grandes conjuntos de dados?

15

Meu grupo de pesquisa se concentra na dinâmica molecular, que obviamente pode gerar gigabytes de dados como parte de uma única trajetória que deve ser analisada.

Vários dos problemas com os quais estamos preocupados envolvem correlações no conjunto de dados, o que significa que precisamos acompanhar grandes quantidades de dados na memória e analisá-las, em vez de usar uma abordagem mais seqüencial.

O que eu gostaria de saber é quais são as estratégias mais eficientes para lidar com E / S de grandes conjuntos de dados em scripts. Normalmente, usamos scripts baseados em Python porque tornam a codificação do E / S do arquivo muito menos dolorosa do que o C ou o Fortran, mas quando temos dezenas ou centenas de milhões de linhas que precisam ser processadas, não está tão claro qual é a melhor abordagem. . Devemos considerar fazer a entrada do arquivo como parte do código em C ou outra estratégia é mais útil? (Simplesmente pré-carregar toda a matriz na memória será melhor do que uma série de leituras seqüenciais de "chunks" (ordem de megabytes)?

Algumas notas adicionais:

  • Estamos procurando principalmente ferramentas de script para pós-processamento, em vez de ferramentas "on-line" - daí o uso do Python.

  • Como mencionado acima, estamos fazendo simulações de MD. Um tópico de interesse são os cálculos de difusão, para os quais precisamos obter o coeficiente de difusão de Einstein: Isso significa que realmente precisam carregar todos os dados na memória antes de começar o cálculo, todos os blocos de dados (registros de horários individuais) irão interagir entre si.

    D=1 16limΔt(x(t+Δt)-x(t))2
aeismail
fonte

Respostas:

6

Estou assumindo que sua pergunta vem da observação de que a E / S causa uma sobrecarga significativa em toda a sua análise. Nesse caso, você pode tentar sobrepor E / S com computação.

Uma abordagem bem-sucedida depende de como você acessa os dados e da computação realizada nesses dados. Se você puder identificar um padrão ou se o acesso a diferentes regiões dos dados for conhecido antecipadamente, tente pré-buscar os "próximos blocos" de dados em segundo plano enquanto processa os "blocos atuais".

Como um exemplo simples, se você apenas percorrer o arquivo uma vez e processar cada linha ou conjunto de linhas, poderá dividir o fluxo em blocos de linhas (ou MBs). Em seguida, a cada iteração sobre os blocos, você pode carregar o bloco i + 1 durante o processamento do bloco i.

Sua situação pode ser mais complexa e precisar de soluções mais envolvidas. De qualquer forma, a idéia é executar a E / S em segundo plano enquanto o processador possui alguns dados para trabalhar. Se você fornecer mais detalhes sobre o seu problema específico, poderemos dar uma olhada mais profunda nele;)

---- Versão estendida depois de dar mais detalhes ----

Não sei se entendi a notação, mas bem, como você disse, a ideia é uma interação de todos para todos. Você também mencionou que os dados podem caber na RAM. Então, começaria medindo o tempo para carregar todos os dados e o tempo para executar o cálculo. Agora,

  • se a porcentagem de E / S for baixa (baixa, como você não se importa com a sobrecarga, seja ela qual for: 0,5%, 2%, 5%, ...), use apenas a abordagem simples: carregar dados de uma vez e calcule. Você economizará tempo para aspectos mais interessantes de sua pesquisa.

  • se você não puder arcar com as despesas gerais, talvez queira dar uma olhada no que Pedro sugeriu. Lembre-se do que Aron Ahmadia mencionou e teste-o antes de executar uma implementação completa.

  • n2n

    carregar chunk1 e chunk2
    para pedaços i = 1 en
        carregar assincronamente o pedaço i + 1
        para pedaços em j = i + 1 en
            carregar assincronamente o pedaço j + 1
            calcular com os blocos i, j (* para a primeira iteração, esses são os blocos 1 e 2 pré-carregados *)

Nota: este é um pseudocódigo rápido e sujo, seria necessário ajustar os índices.

Para implementar isso, é comum usar o chamado buffer duplo . Grosso modo: divida a memória em dois espaços de trabalho; enquanto os dados estão sendo carregados em segundo plano na área de trabalho 1, o processador está computando com os dados na área de trabalho 2. A cada iteração, troque a função.

Lamento não poder encontrar uma boa referência agora.

[1] Um algoritmo fora do núcleo incorpora algum mecanismo para (eficientemente) lidar com dados que residem no disco. Eles são chamados fora do núcleo, em vez de dentro do núcleo ("in-RAM").

Diego
fonte
7

Eu já tive que lidar com problemas semelhantes antes, e minha solução favorita é usar E / S mapeada em memória , embora em C ...

O princípio por trás disso é bastante simples: em vez de abrir um arquivo e lê-lo, você o carrega diretamente na memória e o acessa como se fosse uma grande variedade. O truque que o torna eficiente é que o sistema operacional não carrega realmente o arquivo , apenas o trata como memória trocada que precisa ser carregada. Quando você acessa qualquer byte no seu arquivo, a página de memória dessa parte do arquivo é trocada na memória. Se você continuar acessando partes diferentes do arquivo e a memória ficar apertada, as partes menos usadas serão trocadas novamente - automaticamente.

Uma rápida pesquisa no Google me diz que isso também está disponível para Python: 16.7. mmap - Suporte a arquivos mapeados na memória , mas não sei o suficiente sobre o Python para saber se é realmente a mesma coisa.

Pedro
fonte
11
Apenas certifique-se de medir e testar antes de implementar algo como mmapno seu código principal. Muitos sistemas operacionais modernos oferecem desempenho semelhante entre os regulares, readcom menos complicações. (Além disso, sim, o mmap no Python fornece uma interface portátil para os mapas de memória do Windows e UNIX).
Aron Ahmadia 06/04/12
1

Talvez você possa usar o Cython nas seções de E / S do arquivo e converter esta parte em código C?

asmático
fonte