Zkuste knihovnu ilock:
from ilock import ILock
with ILock('Unique lock name'):
# The code should be run as a system-wide single instance
...
"Tradiční" unixovou odpovědí je použití zámků souborů. Můžete použít lockf(3)
zamknout části souboru, aby je ostatní procesy nemohly upravovat; velmi častým zneužitím je používat toto jako mutex mezi procesy. Ekvivalent pythonu je fcntl.lockf.
Tradičně zapisujete PID zamykacího procesu do souboru zámku, takže zablokování způsobené procesy odumírajícími při držení zámku jsou identifikovatelné a opravitelné.
Tím získáte, co chcete, protože váš zámek je v globálním jmenném prostoru (systém souborů) a je přístupný všem procesům. Tento přístup má také tu výhodu, že se na vašem zamykání mohou podílet i jiné programy než Python. Nevýhodou je, že pro tento soubor zámku potřebujete místo k životu; některé souborové systémy se také ve skutečnosti nezamykají správně, takže existuje riziko, že se tiše nepodaří dosáhnout vyloučení. Něco vyhrajete, něco prohrajete.
Moje odpověď se překrývá s ostatními odpověďmi, ale jen abych přidal něco, co mohou lidé zkopírovat a vložit, často dělám něco takového.
class Locker:
def __enter__ (self):
self.fp = open("./lockfile.lck")
fcntl.flock(self.fp.fileno(), fcntl.LOCK_EX)
def __exit__ (self, _type, value, tb):
fcntl.flock(self.fp.fileno(), fcntl.LOCK_UN)
self.fp.close()
A pak jej použijte jako:
print("waiting for lock")
with Locker():
print("obtained lock")
time.sleep(5.0)
Chcete-li otestovat, proveďte touch lockfile.lck
poté spusťte výše uvedený kód ve dvou nebo více různých terminálech (ze stejného adresáře).
AKTUALIZACE:smwikipedia zmínila, že mé řešení je specifické pro unix. Nedávno jsem potřeboval přenosnou verzi a přišel jsem s následujícím nápadem z náhodného projektu github. Nejsem si jistý, zda jsou volání seek() potřeba, ale jsou tam, protože Windows API zamyká konkrétní pozici v souboru. Pokud soubor nepoužíváte k ničemu jinému než k zamykání, pravděpodobně můžete hledání odstranit.
if os.name == "nt":
import msvcrt
def portable_lock(fp):
fp.seek(0)
msvcrt.locking(fp.fileno(), msvcrt.LK_LOCK, 1)
def portable_unlock(fp):
fp.seek(0)
msvcrt.locking(fp.fileno(), msvcrt.LK_UNLCK, 1)
else:
import fcntl
def portable_lock(fp):
fcntl.flock(fp.fileno(), fcntl.LOCK_EX)
def portable_unlock(fp):
fcntl.flock(fp.fileno(), fcntl.LOCK_UN)
class Locker:
def __enter__(self):
self.fp = open("./lockfile.lck")
portable_lock(self.fp)
def __exit__(self, _type, value, tb):
portable_unlock(self.fp)
self.fp.close()
Standard POSIX specifikuje meziprocesové semafory, které lze pro tento účel použít. http://linux.die.net/man/7/sem_overview
multiprocessing
modul v Pythonu je postaven na tomto API a dalších. Konkrétně multiprocessing.Lock
poskytuje křížový proces "mutex". http://docs.python.org/library/multiprocessing.html#synchronization-between-processes
UPRAVIT pro odpověď na upravenou otázku:
Ve vašem proof of concept každý proces vytváří Lock()
. Máte tedy dva samostatné zámky. Proto ani jeden proces nečeká. Budete muset sdílet stejný zámek mezi procesy. Sekce, na kterou jsem odkazoval v multiprocessing
dokumentace vysvětluje, jak to udělat.