1. 首页
  2. 运维开发
  3. Python

Python进程文件锁fcntl库使用

我们在写python应用的时候,当涉及到多个进程向同一个文件write(或者read)的情况,如果几个进程同时都对这个文件进行写操作,那么文件的内容就会变得非常混乱,这个时候文件锁就派上用场了。

python中的文件锁,可以保证同时只有一个进程写文件,目前使用的是fcntl这个库,它实际上为 Unix上的ioctl,flock和fcntl 函数提供了一个接口。python通过调用fcntl.flock()函数对文件加锁。

fcntl这个模块是Python自带的,但Windows没有,可以手工下载fcntl.py文件,然后保存到python的Lib目录下。

锁类型

LOCK_SH: 表示要创建一个共享锁,在任意时间内,一个文件的共享锁可以被多个进程拥有
LOCK_EX: 表示创建一个排他锁,在任意时间内,一个文件的排他锁只能被一个进程拥有
LOCK_UN: 表示删除该进程创建的锁(解锁)
LOCK_MAND:它主要是用于共享模式强制锁,它可以与 LOCK_READ 或者 LOCK_WRITE 联合起来使用,从而 表示是否允许并发的读操作或者并发的写操作(尽管在 flock() 的手册页中没有介绍 LOCK_MAND,但是阅读内核源代码就会发现,这在内核中已经实现了)
LOCK_NB: 如果指定此参数,函数不能获得文件锁就立即返回,否则,函数会等待获得文件锁。LOCK_NB可以同LOCK_SH或LOCK_EX进行按位或(|)运算操作。
例如:一个文件设置了排它锁,如果这个锁已经被某个进程获取了,那么其他进程请求获取这个锁的时候将会被阻塞。
如果想要在没有获得这个排他锁的情况下不阻塞那些进程,可以与 LOCK_NB 联合使用,那么系统就不会阻塞该进程。即: fcnt.flock(f,fcntl.LOCK_EX|fcntl.LOCK_NB)

简单使用

import fcntl  
import os, time  
  
FILE = "counter.txt"  
  
if not os.path.exists(FILE):  
    # create the counter file if it doesn't exist  
    file = open(FILE, "w")  
    file.write("0")  
    file.close()  
  
for i in range(20):  
    file = open(FILE, "r+")     #由于flock生成的是劝告锁,不能阻止进程对文件的操作,所以这里可以正常打开文件  
    fcntl.flock(file.fileno(), fcntl.LOCK_EX)   #为了避免同时操作文件,需要程序自己来检查该文件是否已经被加锁。这里如果检查到加锁了,进程会被阻塞      
    print 'acquire lock'  
    counter = int(file.readline()) + 1  
    file.seek(0)  
    file.write(str(counter))  
    print os.getpid(), "=>", counter  
    time.sleep(10)  
    file.close() # unlocks the file  
    print 'release lock'  
    time.sleep(3)

注意点

1、对于文件的 close() 操作会使文件锁失效;
2、同理,进程结束后文件锁失效;
3、flock() 的 LOCK_EX是“劝告锁”,系统内核不会强制检查锁的状态,需要在代码中进行文件操作的地方显式检查才能生效。
4、在给文件加锁之前,一定要保证文件以相应的访问模式打开,例如:
要对一个文件加上共享锁,一定要首先按读模式打开文件;
若要给文件加上排他锁,则首先要按写模式打开对应文件;
若想加两种锁,则需要按读写模式打开。

示例

import fcntl

class Lock(object):
    def __init__(self, file_name):
        self.file_name = file_name
        self.handle = open(file_name, 'w+')

    def lock(self):
        fcntl.flock(self.handle, fcntl.LOCK_EX | fcntl.LOCK_NB)

    def unlock(self):
        fcntl.flock(self.handle, fcntl.LOCK_UN)

    def __del__(self):
        try:
            self.handle.close()
        except:
            pass
1 评论
内联反馈
查看所有评论
下拉通
4 年 前

不知道有没有用的了

联系我们

0574-55011290

QQ:248687950

邮件:admin@nbhao.org

工作时间:周一至周五,9:00-18:00,节假日休息

QR code