質問
Python で書き込むためにファイルをロックする必要があります。複数の Python プロセスから同時にアクセスされます。オンラインでいくつかの解決策を見つけましたが、ほとんどの場合、Unix ベースまたは Windows ベースのみであるため、私の目的には失敗します。
解決
さてさて、私は私が書いたコード<ストライキ> <のhref = "http://www.evanfosmark.com/2009/01/cross-platform-file-locking-support-in-pythonと一緒に行くことになりました/ "のrel = "noreferrer" ここ>、私のウェブサイト上ののストライキ> <のhref =" https://web.archive.org/web/20140531203736/http://www.evanfosmark .COM 80/2009/01 /クロスプラットフォーム・ファイル・ロック・サポート・イン・パイソン/」relが= "noreferrer"> archive.org の上のリンクが死んでいる、ビュー(の上でも利用できるのhref = "https://github.com/dmfrey/FileLock" のrel = "noreferrer">)。私は、次の方法でそれを使用することができます:
from filelock import FileLock
with FileLock("myfile.txt"):
# work with the file as it is now locked
print("Lock acquired.")
他のヒント
クロスプラットフォームのファイルロックモジュールがここにあります: Portalockerする
は、ケビンは複数のプロセスからのファイルへの書き込み、言うようものの、一度あなたが可能で、すべての場合は避けたいものです。
あなたがデータベースにあなたの問題を押し込もできる場合は、、あなたはSQLiteのを使用することができます。これは、同時アクセスをサポートし、独自のロックを処理します。
他のソリューションは、外部のコードベースの多くを引用します。あなたはそれを自分で行うことを好む場合は、ここでのLinux / DOSシステム上のツールをロックし、それぞれのファイルを使用するクロスプラットフォーム・ソリューションのためのいくつかのコードです。
try:
# Posix based file locking (Linux, Ubuntu, MacOS, etc.)
import fcntl, os
def lock_file(f):
fcntl.lockf(f, fcntl.LOCK_EX)
def unlock_file(f):
fcntl.lockf(f, fcntl.LOCK_UN)
except ModuleNotFoundError:
# Windows file locking
import msvcrt, os
def file_size(f):
return os.path.getsize( os.path.realpath(f.name) )
def lock_file(f):
msvcrt.locking(f.fileno(), msvcrt.LK_RLCK, file_size(f))
def unlock_file(f):
msvcrt.locking(f.fileno(), msvcrt.LK_UNLCK, file_size(f))
# Class for ensuring that all file operations are atomic, treat
# initialization like a standard call to 'open' that happens to be atomic.
# This file opener *must* be used in a "with" block.
class AtomicOpen:
# Open the file with arguments provided by user. Then acquire
# a lock on that file object (WARNING: Advisory locking).
def __init__(self, path, *args, **kwargs):
# Open the file and acquire a lock on the file before operating
self.file = open(path,*args, **kwargs)
# Lock the opened file
lock_file(self.file)
# Return the opened file object (knowing a lock has been obtained).
def __enter__(self, *args, **kwargs): return self.file
# Unlock the file and close the file object.
def __exit__(self, exc_type=None, exc_value=None, traceback=None):
# Flush to make sure all buffered contents are written to file.
self.file.flush()
os.fsync(self.file.fileno())
# Release the lock on the file.
unlock_file(self.file)
self.file.close()
# Handle exceptions that may have come up during execution, by
# default any exceptions are raised to the user.
if (exc_type != None): return False
else: return True
さて、AtomicOpen
は1つが正常にwith
文を使用しopen
ブロックで使用することができます。
警告:のWindowsとのPython上で動作するの終了の前にクラッシュした場合、私はロックの挙動がどうなるかわからない、と呼ばれている。
。警告:のここに設けられたロックは絶対、助言ではありません。すべての潜在的に競合するプロセスは、「AtomicOpen」クラスを使用する必要があります。
私が好むの ロックファイルにする - プラットフォームに依存しないファイルロック
ロックはプラットフォームとデバイスによって異なりますが、一般に、いくつかのオプションがあります。
- flock() または同等の関数 (OS がサポートしている場合) を使用します。これは勧告的なロックであり、ロックをチェックしない限り無視されます。
- ロック、コピー、移動、ロック解除の方法を使用します。この方法では、ファイルをコピーし、新しいデータを書き込んでから、それを移動します (コピーではなく移動します。Linux では移動はアトミックな操作です。OS を確認してください)。ロックファイルの存在。
- ディレクトリを「ロック」として使用します。NFS は flock() をサポートしていないため、NFS に書き込む場合はこれが必要です。
- プロセス間で共有メモリを使用する可能性もありますが、私はそれを試したことはありません。それは非常に OS 固有です。
これらすべての方法では、ロックの取得とテストにスピン ロック (失敗後の再試行) 手法を使用する必要があります。これにより、同期ミスが発生する可能性がわずかに残りますが、通常は十分に小さいため、大きな問題にはなりません。
クロスプラットフォームのソリューションを探している場合は、他のメカニズムを介して別のシステムにログを記録することをお勧めします (次善の方法は上記の NFS テクニックです)。
sqlite には通常のファイルと同じ NFS 上の制約が適用されるため、ネットワーク共有上の sqlite データベースに書き込んで無料で同期を取得することはできないことに注意してください。
OSレベルでの単一のファイルへのアクセスを調整することで、おそらく解決したくない問題のすべての種類をはらんでいる。
あなたの最善の策は、そのファイルへの読み取り/書き込みアクセスを座標別のプロセスを持っている。
ファイルをロックし、通常は、プラットフォーム固有の操作ですので、あなたは、異なるオペレーティングシステム上で実行されている可能性を可能にする必要があるかもしれません。たとえばます:
import os
def my_lock(f):
if os.name == "posix":
# Unix or OS X specific locking here
elif os.name == "nt":
# Windows specific locking here
else:
print "Unknown operating system, lock unavailable"
私は、同じディレクトリ/フォルダとログのエラーの中から、同じプログラムの複数のコピーを実行し、このような状況に取り組んできました。私のアプローチは、ログファイルを開く前にディスクに「ロックファイル」を書くことでした。そのターン進む前に「ロックファイル」の存在をチェックし、待機「がファイルをロック」が存在します。
ここでは、コードは次のとおりです。
def errlogger(error):
while True:
if not exists('errloglock'):
lock = open('errloglock', 'w')
if exists('errorlog'): log = open('errorlog', 'a')
else: log = open('errorlog', 'w')
log.write(str(datetime.utcnow())[0:-7] + ' ' + error + '\n')
log.close()
remove('errloglock')
return
else:
check = stat('errloglock')
if time() - check.st_ctime > 0.01: remove('errloglock')
print('waiting my turn')
EDIT --- I上記の古いロックについてのコメントのいくつかの上で考えた後の陳腐化のためのチェックを追加するコードを編集した「ロックファイルを。」私のシステムでこの機能の数千回の反復を与え、前だけから0.002066 ...秒の平均タイミングます:
lock = open('errloglock', 'w')
の直後に
remove('errloglock')
私は、私は古さを示し、問題の状況を監視するために、5倍の量で開始します考え出します。
はまた、私はタイミングで働いていたとして、私は本当に必要ではなかったコードのビットを持っていたことに気づいます:
lock.close()
私はすぐに開いている文を、次のいたので、私はこの編集でそれを削除しました。
の シナリオ それは次のようなものです:ユーザーは何かを行うためにファイルをリクエストします。その後、ユーザーが同じリクエストを再度送信すると、最初のリクエストが完了するまで 2 番目のリクエストは実行されないことがユーザーに通知されます。そのため、私はロック機構を使用してこの問題に対処しています。
私の作業コードは次のとおりです。
from lockfile import LockFile
lock = LockFile(lock_file_path)
status = ""
if not lock.is_locked():
lock.acquire()
status = lock.path + ' is locked.'
print status
else:
status = lock.path + " is already locked."
print status
return status
シンプルで機能するものを見つけました(!) 実装 グリズルドパイソンから。
単純な os.open(..., O_EXCL) + os.close() の使用は Windows では機能しませんでした。
あなたは pylocker に非常に便利かもしれません。ファイルまたは一般的機構をロックするためにロックするために使用することができ、一度に複数のPythonのプロセスからアクセスすることができます。
あなたは、単にファイルをロックしたい場合は、それがどのように動作するかここにあります:
import uuid
from pylocker import Locker
# create a unique lock pass. This can be any string.
lpass = str(uuid.uuid1())
# create locker instance.
FL = Locker(filePath='myfile.txt', lockPass=lpass, mode='w')
# aquire the lock
with FL as r:
# get the result
acquired, code, fd = r
# check if aquired.
if fd is not None:
print fd
fd.write("I have succesfuly aquired the lock !")
# no need to release anything or to close the file descriptor,
# with statement takes care of that. let's print fd and verify that.
print fd