الثعبان: وحدة لخلق lockfile استنادا PID؟
سؤال
وأنا أكتب نصي بيثون قد تكون أو لا (اعتمادا على مجموعة من الأشياء) تشغيل لفترة طويلة، وأود أن تأكد من أن حالات متعددة (التي عبر كرون) لا خطوة على بعضها البعض أصابع القدم. طريقة منطقية للقيام بذلك ويبدو أن lockfile القائم على PID ... ولكن لا أريد لإعادة اختراع العجلة إذا كان هناك بالفعل رمز للقيام بذلك.
وهكذا، هناك وحدة بيثون هناك والتي ستدير تفاصيل lockfile استنادا PID؟
المحلول
إذا يمكنك استخدام GLPv2 بشكل، زئبقي على وحدة لذلك:
http://bitbucket.org/mirror/mercurial/src/ غيض / زئبقي / lock.py
والاستخدام مثال:
from mercurial import error, lock
try:
l = lock.lock("/path/to/lock", timeout=600) # wait at most 10 minutes
# do something
except error.LockHeld:
# couldn't take the lock
else:
l.release()
نصائح أخرى
وهذا قد يكون عونا لك: lockfile
وأعتقد أنك سوف تجد ما يلزم من المعلومات هنا . تشير الصفحة في السؤال على مجموعة لبناء الشياطين في بيثون: هذه العملية تنطوي خلق lockfile PID
ولقد كنت مستاء جدا مع كل من هؤلاء، لذلك أنا كتبت هذا:
class Pidfile():
def __init__(self, path, log=sys.stdout.write, warn=sys.stderr.write):
self.pidfile = path
self.log = log
self.warn = warn
def __enter__(self):
try:
self.pidfd = os.open(self.pidfile, os.O_CREAT|os.O_WRONLY|os.O_EXCL)
self.log('locked pidfile %s' % self.pidfile)
except OSError as e:
if e.errno == errno.EEXIST:
pid = self._check()
if pid:
self.pidfd = None
raise ProcessRunningException('process already running in %s as pid %s' % (self.pidfile, pid));
else:
os.remove(self.pidfile)
self.warn('removed staled lockfile %s' % (self.pidfile))
self.pidfd = os.open(self.pidfile, os.O_CREAT|os.O_WRONLY|os.O_EXCL)
else:
raise
os.write(self.pidfd, str(os.getpid()))
os.close(self.pidfd)
return self
def __exit__(self, t, e, tb):
# return false to raise, true to pass
if t is None:
# normal condition, no exception
self._remove()
return True
elif t is PidfileProcessRunningException:
# do not remove the other process lockfile
return False
else:
# other exception
if self.pidfd:
# this was our lockfile, removing
self._remove()
return False
def _remove(self):
self.log('removed pidfile %s' % self.pidfile)
os.remove(self.pidfile)
def _check(self):
"""check if a process is still running
the process id is expected to be in pidfile, which should exist.
if it is still running, returns the pid, if not, return False."""
with open(self.pidfile, 'r') as f:
try:
pidstr = f.read()
pid = int(pidstr)
except ValueError:
# not an integer
self.log("not an integer: %s" % pidstr)
return False
try:
os.kill(pid, 0)
except OSError:
self.log("can't deliver signal to %s" % pid)
return False
else:
return pid
class ProcessRunningException(BaseException):
pass
ولاستخدامها شيء من هذا القبيل:
try:
with Pidfile(args.pidfile):
process(args)
except ProcessRunningException:
print "the pid file is in use, oops."
وأنا أعلم أن هذا هو موضوع قديم، ولكن أنا أيضا خلق القفل البسيطة التي تعتمد فقط على الثعبان المكتبات الأم:
import fcntl
import errno
class FileLock:
def __init__(self, filename=None):
self.filename = os.path.expanduser('~') + '/LOCK_FILE' if filename is None else filename
self.lock_file = open(self.filename, 'w+')
def unlock(self):
fcntl.flock(self.lock_file, fcntl.LOCK_UN)
def lock(self, maximum_wait=300):
waited = 0
while True:
try:
fcntl.flock(self.lock_file, fcntl.LOCK_EX | fcntl.LOCK_NB)
return True
except IOError as e:
if e.errno != errno.EAGAIN:
raise e
else:
time.sleep(1)
waited += 1
if waited >= maximum_wait:
return False
وهناك صفة على ActiveState على خلق lockfiles .
لتوليد اسم الملف يمكنك استخدام os.getpid () أ > للحصول على PID.