最近在写python项目的时候遇到一个问题
有这样一个python脚本:
1 脚本功能
A 监控网卡的实时流量,如果该流量超过设定阀值就去增加带宽(购买带宽包)
B 脚本放在 crontab 中,并且是每分钟执行一次
2 遇到问题
在执行脚本的过程中,如果一分钟内该程序没有执行完,就可能会有两个相同的代码同时执行,导致的问题是 会同时购买两次带宽包,这样会造成资源的浪费。
3 解决思路
A 可以调整crontab,增加代码执行的时间(治标不治本)
B 为该程序加锁,同一时间只允许运行一个监控程序。
4 解决步骤
因此,怎么为程序加锁,还要尽量减少对源代码的更改,是问题的关键,我这里使用到了python的装饰器。
思路是这样的:
A 打开一个 xx.pid 文件,并为这个文件加上锁
B 获取当前执行程序的PID,并写入到 xx.pid文件中
C 执行程序,执行结束后关闭并且删除该xx.pid文件
5 上代码
#!/usr/bin/python # -*- coding: utf-8 -*- import fcntl from functools import wraps import os def singleton(pid_filename): def decorator(f): @wraps(f) def decorated(*args, **kwargs): pid = str(os.getpid()) pidfile = open(pid_filename, ‘a+‘) try: #创建一个排他锁,并且所被锁住其他进程不会阻塞 fcntl.flock(pidfile.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB) except IOError: return pidfile.seek(0) pidfile.truncate() # 清空文件 pidfile.write(pid) pidfile.flush() pidfile.seek(0) ret = f(*args, **kwargs) try: pidfile.close() except IOError, err: # 可能的错误 IOError: [Errno 9] Bad file descriptor if err.errno != 9: return os.remove(pid_filename) return ret return decorated return decorator
注意:
fcntl 仅在 linux系统中使用,在windows中无效
6 简单用例
@singleton(‘/tmp/add_bandwidth.pid‘) def add_bandwidth(): pass
7 代码解析
这里使用到了python 的fcntl模块 -- python中给文件加锁
简单示例:
>>> import fcntl >>> f = open(‘test.txt‘) >>> fcntl.flock(f.fileno(),fcntl.LOCK_EX) #对文件加锁 >>> fcntl.flock(f.fileno(),fcntl.LOCK_UN) #对文件解锁
----------------------
fcntl模块 中的flock(fd, operation):
参数 fd 表示文件描述符;
参数 operation 指定要进行的锁操作,该参数的取值有如下几种:
operation : 包括:
fcntl.LOCK_UN 解锁
fcntl.LOCK_EX 排他锁
fcntl.LOCK_SH 共享锁
fcntl.LOCK_NB 非阻塞锁
LOCK_SH 共享锁:所有进程没有写访问权限,即使是加锁进程也没有。所有进程有读访问权限。
LOCK_EX 排他锁:除加锁进程外其他进程没有对已加锁文件读写访问权限。
LOCK_NB 非阻塞锁:如果指定此参数,函数不能获得文件锁就立即返回,否则,函数会等待获得文件锁。
LOCK_NB可以同LOCK_SH或LOCK_NB进行按位或(|)运算操作。 fcnt.flock(f,fcntl.LOCK_EX|fcntl.LOCK_NB)
注意:
1. 对于文件的 close() 操作会使文件锁失效;
2. 同理,进程结束后文件锁失效;3. flock() 的 LOCK_EX是“劝告锁”,系统内核不会强制检查锁的状态,需要在代码中进行文件操作的地方显式检查才能生效。
详情请查看官方文档:
https://docs.python.org/2/library/fcntl.html#fcntl.flock
本文出自 “一个奋斗的小运维” 博客,请务必保留此出处http://yucanghai.blog.51cto.com/5260262/1733004
原文地址:http://yucanghai.blog.51cto.com/5260262/1733004