2022年 11月 4日

python文件锁

一个lock file的python
实现

此代码基于实际业务出发,且已应用于线上生产环境(已脱敏)

需求背景:python脚本项目,实现同一个脚本不能同时执行,需要在具体的脚本执行前加锁控制

需求实现方案:

        1.基于文件的python的文件锁

        2.基于端口号的端口锁(已测试在并发环境下锁不住)

python文件锁实现方案:

        如果多个进程,或者多个独立程序要写同一个文件,那么就存在大家同时写文件的可能,这时就需要具体的脚本执行前加锁,控制并发
文件名:lockfile.py

  1. import os
  2. import time
  3. import errno
  4. class FileLockException(Exception):
  5. pass
  6. class FileLock(object):
  7. def __init__(self, file_name, timeout=10, delay=.05):
  8. self.is_locked = False
  9. # 将锁文件放置统一位置,方便管理
  10. dirs = sys.path[0] + "/lock"
  11. if not os.path.exists(dirs):
  12. os.makedirs(dirs)
  13. self.lockfile = os.path.join(dirs, "%s.lock" % file_name)
  14. self.file_name = file_name
  15. self.timeout = timeout
  16. self.delay = delay
  17. def acquire(self):
  18. start_time = time.time()
  19. while True:
  20. try:
  21. #独占式打开文件
  22. #os.O_RDWR : 以读写的方式打开
  23. #os.O_CREAT: 创建并打开一个新文件
  24. #os.O_EXCL: 如果指定的文件存在,返回错误
  25. self.fd = os.open(self.lockfile, os.O_CREAT|os.O_EXCL|os.O_RDWR)
  26. break;
  27. except OSError as e:
  28. if e.errno != errno.EEXIST:
  29. raise
  30. if (time.time() - start_time) >= self.timeout:
  31. raise FileLockException("Timeout occured.")
  32. time.sleep(self.delay)
  33. self.is_locked = True
  34. def release(self):
  35. #关闭文件,删除文件
  36. if self.is_locked:
  37. os.close(self.fd)
  38. os.unlink(self.lockfile)
  39. self.is_locked = False
  40. def __enter__(self):
  41. if not self.is_locked:
  42. self.acquire()
  43. return self
  44. def __exit__(self, type, value, traceback):
  45. if self.is_locked:
  46. self.release()
  47. def __del__(self):
  48. self.release()

测试类test_lock.py

  1. def test_lock(i):
  2. with FileLock('myfile.txt', 2):
  3. print("%s get lock success, %s" % (str(i), str(time.time())))
  4. time.sleep(3)
  5. if __name__ == '__main__':
  6. for i in range(5):
  7. threading.Thread(target=test_lock, args={i}).start()
  8. time.sleep(5)

用法比较有意思,使用with关键字。对with关键字来说,FileLock类先执行__enter__函数,然后,执行with块里的那些代码,执行完了之后,再执行__exit__函数,等价于相当于如下形式:

  1. try:
  2.       执行 __enter__的内容
  3.       执行 with_block.
  4. finally:
  5.       执行 __exit__内容

FileLock在__enter__函数独占式创建或打开一个文件,这个文件不会被其他程序或者进程再次创建或者打开,由此形成lock,执行完代码,在__exit__里,关闭并删除文件

后续测试内容需补充

文章借鉴:python lockfile(文件锁)