欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

巧妙使用fcntl和atexit实现多进程同步

最编程 2024-01-15 17:21:44
...

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)

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

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)  # 在此进程结束时释放掉锁