一个lock file的python
实现
此代码基于实际业务出发,且已应用于线上生产环境(已脱敏)
需求背景:python脚本项目,实现同一个脚本不能同时执行,需要在具体的脚本执行前加锁控制
需求实现方案:
1.基于文件的python的文件锁
2.基于端口号的端口锁(已测试在并发环境下锁不住)
python文件锁实现方案:
如果多个进程,或者多个独立程序要写同一个文件,那么就存在大家同时写文件的可能,这时就需要具体的脚本执行前加锁,控制并发
文件名:lockfile.py
- import os
- import time
- import errno
-
- class FileLockException(Exception):
- pass
-
- class FileLock(object):
-
- def __init__(self, file_name, timeout=10, delay=.05):
-
- self.is_locked = False
- # 将锁文件放置统一位置,方便管理
- dirs = sys.path[0] + "/lock"
- if not os.path.exists(dirs):
- os.makedirs(dirs)
- self.lockfile = os.path.join(dirs, "%s.lock" % file_name)
- self.file_name = file_name
- self.timeout = timeout
- self.delay = delay
-
-
- def acquire(self):
- start_time = time.time()
- while True:
- try:
- #独占式打开文件
- #os.O_RDWR : 以读写的方式打开
- #os.O_CREAT: 创建并打开一个新文件
- #os.O_EXCL: 如果指定的文件存在,返回错误
- self.fd = os.open(self.lockfile, os.O_CREAT|os.O_EXCL|os.O_RDWR)
- break;
- except OSError as e:
- if e.errno != errno.EEXIST:
- raise
- if (time.time() - start_time) >= self.timeout:
- raise FileLockException("Timeout occured.")
- time.sleep(self.delay)
- self.is_locked = True
-
-
- def release(self):
- #关闭文件,删除文件
- if self.is_locked:
- os.close(self.fd)
- os.unlink(self.lockfile)
- self.is_locked = False
-
-
- def __enter__(self):
- if not self.is_locked:
- self.acquire()
- return self
-
-
- def __exit__(self, type, value, traceback):
- if self.is_locked:
- self.release()
-
-
- def __del__(self):
- self.release()
测试类test_lock.py
- def test_lock(i):
- with FileLock('myfile.txt', 2):
- print("%s get lock success, %s" % (str(i), str(time.time())))
- time.sleep(3)
-
-
- if __name__ == '__main__':
- for i in range(5):
- threading.Thread(target=test_lock, args={i}).start()
- time.sleep(5)
用法比较有意思,使用with关键字。对with关键字来说,FileLock类先执行__enter__函数,然后,执行with块里的那些代码,执行完了之后,再执行__exit__函数,等价于相当于如下形式:
- try:
- 执行 __enter__的内容
- 执行 with_block.
- finally:
- 执行 __exit__内容
FileLock在__enter__函数独占式创建或打开一个文件,这个文件不会被其他程序或者进程再次创建或者打开,由此形成lock,执行完代码,在__exit__里,关闭并删除文件
后续测试内容需补充
文章借鉴:python lockfile(文件锁)