python实现文件锁

之前写过一篇用python实现多进程与多线程的文章,在使用多进程或者多线程的情况下,使用锁来实现互斥以避免同时对资源执行读和写就成为一个不可避免的事情。 对于一般的变量资源来说实现互斥锁很简单,使用multiprocessing.Lock类或者threading.Lock即可。但是如果我们要实现互斥的是文件呢?

写这篇文章的初衷是我没有找到现成的库可以用,所以特意自己写了一个想贴出来。但是写到一半的时候发现了filelock库可以解决这个问题,使用起来要比自己写的更好一些。索性就把原来写的全都删了,分享一下用filelock实现文件锁的方法。

安装

使用pip或者conda等安装filelock即可。

1
pip install filelock

使用

这里将介绍一下用filelock模块实现文件锁的基本用法。

导入接口

1
from filelock import FileLock

文件和锁文件

1
2
file = "file.txt"
lockfile = file + ".lock"

这里的文件file是我们要实现互斥锁定的文件。 锁文件lockfile用于确定是否允许进程或者线程访问该文件,具体机制我们可以不必关心,能够正确创建的使用就可以了。

实例化锁对象

1
lock = FileLock(lockfile)

实例化出来一个锁对象lock,注意这里的参数是锁文件lockfile而不是文件filelock在上锁的时候,如果文件已经被其他对象上了锁,那么将一直等待到文件被其他对象释放锁后再上锁。如果不想在获取不到锁的时候永远等待下去,可以如下实例化锁对象:

1
lock = FileLock(lockfile, timeout = 5)

这时,lock在上锁的时候,如果文件已经被其他对象上了锁,那么在5秒内如果文件被其他对象释放锁,lock会对其上锁;否则就会因超时而报错退出。

锁的获取和释放

1
2
3
lock.acquire()
# do something...
lock.release()

使用方法很直观,acquire()方法用于获取锁,release()方法用于释放锁。

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
from filelock import FileLock

file = "file.txt"
lockfile = file + ".lock"

lock = FileLock(lockfile)
lock.acquire()
try:
print("acquire the lock!")
# do something to the file...
finally:
lock.release()
print("release the lock!")

例子

这里,我们将分别跑两个相同的脚本main1.pymain2.py以模拟多进程,这两个脚本均试图排他的获取文件file.txtmain1.pymain2.py中的内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import time
from filelock import FileLock

file = "file.txt"
lockfile = "file.txt.lock"

lock = FileLock(lockfile)

lock.acquire()
try:
# do something to the file...
time_now = time.strftime('%H:%M:%S', time.localtime())
print(time_now + ": acquire the lock!")
time.sleep(5)
finally:
lock.release()
time_now = time.strftime('%H:%M:%S', time.localtime())
print(time_now + ": release the lock!")

先后将main1.pymain2.py跑起来,输出如下: file_lock_result

显然,main1.py先完成了对文件上锁,main2.py就一直处于等待中,一直到main1.py释放了锁,main2.py实现了文件上锁,从而实现了对文件的互斥性访问。