Mantendo dados na memória sincronizados com um arquivo para um script python de longa execução

StackOverflow https://stackoverflow.com/questions/4262403

Pergunta

Eu tenho um script python (2.7) que atua como um servidor e, portanto, será executado por períodos muito longos. Esse script possui vários valores para acompanhar os quais podem mudar a qualquer momento com base na entrada do cliente.

O que estou idealmente depois é algo que pode manter uma estrutura de dados python (com valores de tipos dict, list, unicode, int e float -JSON, basicamente) na memória, deixando-me atualizá-lo como eu quiser (exceto referenciar qualquer uma das instâncias do tipo de referência mais de uma vez), mantendo esses dados atualizados em um arquivo legível pelo homem, de modo que mesmo se o O plugue de energia foi puxado, o servidor poderia apenas iniciar e continuar com os mesmos dados.

Eu sei que estou basicamente falando sobre um banco de dados, mas os dados que estou mantendo serão muito simples e provavelmente menos de 1 kb na maioria das vezes, por isso estou procurando a solução mais simples possível que possa me fornecer o descrito integridade de dados. Existem bibliotecas boas do Python (2.7) que me permitem fazer algo assim?

Foi útil?

Solução

Eu concordo que você não precisa de um banco de dados totalmente soprado, como Parece que tudo o que você deseja são gravações de arquivo atômico. Você precisa resolver esse problema em duas partes, serialização/desserialização e escrita atômica.

Para a primeira seção, json, ou pickle provavelmente são formatos adequados para você. JSON tem a vantagem de ser legível por humanos. Não parece que esse seja o principal problema que você está enfrentando.

Depois de serializar seu objeto para uma string, Use o seguinte procedimento para escrever um arquivo para disco atomicamente, assumindo um único escritor simultâneo (pelo menos no Posix, veja abaixo):

import os, platform
backup_filename = "output.back.json"
filename = "output.json"

serialised_str = json.dumps(...)
with open(backup_filename, 'wb') as f:
     f.write(serialised_str)
if platform.system() == 'Windows':
     os.unlink(filename)
os.rename(backup_filename, filename)

Enquanto os.rename O IS substitui um arquivo existente e é atômico no Posix, infelizmente esse não é o caso no Windows. No Windows, existe a possibilidade de que os.unlink terá sucesso, mas os.rename falhará, o que significa que você tem apenas backup_filename e não filename. Se você estiver segmentando janelas, precisará considerar essa possibilidade quando estiver verificando a existência de filename.

Se houver a possibilidade de mais de um escritor simultâneo, você deverá considerar um construto de sincronização.

Outras dicas

Bem, como você sabe que estamos basicamente falando de um banco de dados, embora muito simples, você provavelmente não ficará surpreso por sugerir que você dê uma olhada no sqlite3 módulo.

Alguma razão para o requisito legível por humanos?

Eu sugiro procurar o SQLite para uma solução simples de banco de dados ou em pickle para uma maneira simples de serializar objetos e escrevê -los no disco. Nem é particularmente legível humano.

Outras opções são JSON, ou XML, como você sugeriu - use o módulo JSON embutido para serializar os objetos em seriicar e escrevê -lo no disco. Ao iniciar, verifique a presença desse arquivo e carregue os dados, se necessário.

De documentos:

>>> import json
>>> print json.dumps({'4': 5, '6': 7}, sort_keys=True, indent=4)
{
    "4": 5,
    "6": 7
}

Como você mencionou que seus dados são pequenos, eu iria com uma solução simples e usaria o salmoura módulo, que permite despejar um objeto Python em uma linha muito facilmente.

Então você acabou de configurar um Fio Isso salva seu objeto em um arquivo em intervalos de tempo definidos.

Não é uma solução "biblioteca", mas - se eu entender seus requisitos - simples o suficiente para você não precisar de uma.

EDIT: Você mencionou que queria cobrir o caso que ocorre um problema durante a própria gravação, tornando -o uma transação atômica efetivamente. Nesse caso, o caminho tradicional a percorrer é usar "recuperação baseada em log". Ele está essencialmente escrevendo um registro em um arquivo de log dizendo que "a transação de gravação iniciou" e, em seguida, escrevendo "Write Transaction Comited" quando terminar. Se um "iniciado" não tiver "commit correspondente", você reverte.

Nesse caso, concordo que você pode estar melhor com um banco de dados simples como o SQLite. Pode ser um leve exagero, mas, por outro lado, implementar a atomicidade pode estar reinventando um pouco a roda (e não encontrei bibliotecas óbvias que o façam por você).

Se você decidir seguir o caminho astuto, esse tópico será abordado no capítulo de sincronização do processo do livro de sistemas operacionais da Silberschatz, na seção "Transações atômicas".

Uma alternativa muito simples (embora talvez não "transacional perfeita") seja apenas para gravar em um novo arquivo todas as vezes, para que, se alguém corromper, você tenha um histórico. Você pode até adicionar uma soma de verificação a cada arquivo para determinar automaticamente se está quebrado.

Você está perguntando como implementar um banco de dados que fornece ÁCIDO Garantias, mas você não forneceu um bom motivo para que não possa usar um prontuário. O SQLite é perfeito para esse tipo de coisa e oferece essas garantias.

No entanto, existe Kirbybase. Eu nunca usei e acho que não faz garantias de ácido, mas tem algumas das características que você está procurando.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top