Preciso bloquear um arquivo para escrever em Python. Ele será acessado de vários processos Python de uma só vez. Encontrei algumas soluções on-line, mas a maioria falha para meus propósitos, pois geralmente são baseadas apenas em Unix ou Windows.
python
file-locking
Evan Fosmark
fonte
fonte
Há um módulo de bloqueio de arquivos de plataforma cruzada aqui: Portalocker
Embora, como Kevin diz, gravar em um arquivo de vários processos ao mesmo tempo seja algo que você deseja evitar, se possível.
Se você pode colocar o seu problema em um banco de dados, pode usar o SQLite. Ele suporta acesso simultâneo e lida com seu próprio bloqueio.
fonte
As outras soluções citam muitas bases de código externas. Se você preferir fazê-lo, aqui está um código para uma solução de plataforma cruzada que usa as respectivas ferramentas de bloqueio de arquivos nos sistemas Linux / DOS.
Agora,
AtomicOpen
pode ser usado em umwith
bloco em que normalmente se usaria umaopen
instrução.AVISO: Se a execução no Windows e no Python falharem antes da saída ser chamada, não tenho certeza de qual seria o comportamento do bloqueio.
AVISO: O bloqueio fornecido aqui é um aviso, não absoluto. Todos os processos potencialmente concorrentes devem usar a classe "AtomicOpen".
fonte
unlock_file
arquivo no linux não deve ligarfcntl
novamente com aLOCK_UN
bandeira?__exit__
vocêclose
fora da fechadura depoisunlock_file
. Acredito que o tempo de execução possa liberar (ou seja, gravar) dados duranteclose
. Eu acredito que é precisoflush
efsync
sob o bloqueio para garantir que nenhum dado adicional seja gravado fora do bloqueio duranteclose
.flush
efsync
. Adicionei as duas linhas que você sugeriu antes de ligarunlock
. Testei novamente e a condição de corrida parece estar resolvida.Eu prefiro lockfile - bloqueio de arquivo independente de plataforma
fonte
Estive procurando várias soluções para fazer isso e minha escolha foi oslo.concurrency
É poderoso e relativamente bem documentado. É baseado em fixadores.
Outras soluções:
fonte
filelock
(Última versão: 18 de maio de 2019 no momento do comentário)O bloqueio é específico da plataforma e do dispositivo, mas geralmente você tem algumas opções:
Para todos esses métodos, você precisará usar uma técnica de bloqueio de rotação (repetir após falha) para adquirir e testar o bloqueio. Isso deixa uma pequena janela para sincronização incorreta, mas geralmente é pequena o suficiente para não ser um problema importante.
Se você está procurando uma solução que seja multiplataforma, é melhor fazer logon em outro sistema por outro mecanismo (a próxima melhor coisa é a técnica NFS acima).
Observe que o sqlite está sujeito às mesmas restrições do NFS que os arquivos normais, portanto, você não pode gravar em um banco de dados do sqlite em um compartilhamento de rede e obter sincronização gratuitamente.
fonte
os.rename
agora é atômica no Win32 desde o Python 3.3: bugs.python.org/issue8828A coordenação do acesso a um único arquivo no nível do sistema operacional está repleta de todos os tipos de problemas que você provavelmente não deseja resolver.
Sua melhor aposta é ter um processo separado que coordene o acesso de leitura / gravação a esse arquivo.
fonte
flock
. Uma abordagem de "role seus próprios mutexes e um processo de daemon para gerenciá-los" parece ser uma abordagem bastante extrema e complicada a ser tomada para resolver ... um problema que você não nos falou, mas que sugere assustadoramente.O bloqueio de um arquivo geralmente é uma operação específica da plataforma; portanto, talvez seja necessário permitir a execução em diferentes sistemas operacionais. Por exemplo:
fonte
Eu tenho trabalhado em uma situação como essa em que executo várias cópias do mesmo programa de dentro do mesmo diretório / pasta e erros de log. Minha abordagem foi gravar um "arquivo de bloqueio" no disco antes de abrir o arquivo de log. O programa verifica a presença do "arquivo de bloqueio" antes de continuar e aguarda sua vez se o "arquivo de bloqueio" existir.
Aqui está o código:
EDITAR --- Depois de refletir sobre alguns dos comentários sobre bloqueios obsoletos acima, editei o código para adicionar uma verificação de robustez do "arquivo de bloqueio". O tempo de vários milhares de iterações dessa função no meu sistema deu uma média de 0,002066 ... segundos antes:
logo depois:
então imaginei que começaria com 5 vezes esse valor para indicar a rigidez e monitorar a situação quanto a problemas.
Além disso, ao trabalhar com o tempo, percebi que tinha um pouco de código que não era realmente necessário:
que eu tinha imediatamente após a declaração aberta, por isso a removi nesta edição.
fonte
Para adicionar à resposta de Evan Fossmark , aqui está um exemplo de como usar o filelock :
Qualquer código dentro do
with lock:
bloco é seguro para threads, o que significa que será concluído antes que outro processo tenha acesso ao arquivo.fonte
O cenário é o seguinte: O usuário solicita um arquivo para fazer alguma coisa. Em seguida, se o usuário enviar a mesma solicitação novamente, ele informará que a segunda solicitação não será feita até que a primeira solicitação seja concluída. É por isso que eu uso o mecanismo de bloqueio para lidar com esse problema.
Aqui está o meu código de trabalho:
fonte
Eu encontrei uma implementação simples e trabalhada (!) Do grizzled-python.
O uso simples os.open (..., O_EXCL) + os.close () não funcionou no Windows.
fonte
Você pode achar o pylocker muito útil. Ele pode ser usado para bloquear um arquivo ou para mecanismos de bloqueio em geral e pode ser acessado a partir de vários processos Python ao mesmo tempo.
Se você simplesmente deseja bloquear um arquivo, veja como ele funciona:
fonte