fcntl(文件上锁)&& atexit 妙用--多进程锁
2020-03-03 本文已影响0人
周周周__
fcntl
一、python中的文件锁
我们在写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,但是阅读内核源代码就会发现,这在内核中已经实现了)
ps:LOCK_NB: 如果指定此参数,函数不能获得文件锁就立即返回,否则,函数会等待获得文件锁。LOCK_NB可以同LOCK_SH或LOCK_EX进行按位或(|)运算操作
。
例如:一个文件设置了排它锁,如果这个锁已经被某个进程获取了,那么其他进程请求获取这个锁的时候将会被阻塞。
如果想要在没有获得这个排他锁的情况下不阻塞那些进程,可以与 LOCK_NB 联合使用,那么系统就不会阻塞该进程。即: fcnt.flock(f,fcntl.LOCK_EX|fcntl.LOCK_NB)
三、注意点
- 对于文件的 close() 操作会使文件锁失效;
- 同理,进程结束后文件锁失效;
- flock() 的 LOCK_EX是“劝告锁”,系统内核不会强制检查锁的状态,需要在代码中进行文件操作的地方显式检查才能生效。
- 在给文件加锁之前,一定要保证文件以相应的访问模式打开,
例如:要对一个文件加上共享锁,一定要首先按读模式打开文件;若要给文件加上排他锁,则首先要按写模式打开对应文件;若想加两种锁,则需要按读写模式打开.*
atexit
python atexit 模块定义了一个 register 函数,用于在 python 解释器中注册一个退出函数,这个函数在解释器正常终止时自动执行,一般用来做一些资源清理的操作。 atexit 按注册的相反顺序执行这些函数; 例如注册A、B、C,在解释器终止时按顺序C,B,A运行。
PS:如果程序是非正常crash,或者通过os._exit()退出,注册的退出函数将不会被调用
。
装饰器
# 装饰器法
import os
from atexit import register
def main():
print('no atexit .')
@register
def atexit1():
print('atexit .')
if __name__ == '__main__':
main()
传参
# 传参
import os
from atexit import register
def main():
print('atexit ')
def goodbye(name, adjective):
print('Goodbye, %s, it was %s to meet you.' % (name, adjective))
if __name__ == '__main__':
register(goodbye, adjective='nice', name='Donny')
main()
exit(1) #程序退出了
print ("chegn xu")
多进程文件锁
fcntl = __import__("fcntl")
f = open('scheduler.lock', 'wb') # 打开锁文件
try:
fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB) # 注册文件锁
scheduler.init_app(app)
scheduler.start()
app.logger.debug('Scheduler Started,---------------')
except:
pass
def unlock():
fcntl.flock(f, fcntl.LOCK_UN)
f.close()
atexit.register(unlock) # 在此进程结束时释放掉锁