本文目录导读:

在Python中规避定时任务重复执行,主要有以下几种常用方法:
文件锁(File Lock)
import os
import fcntl
import time
def acquire_lock():
lock_file = '/tmp/my_script.lock'
try:
fd = open(lock_file, 'w')
fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
return fd
except IOError:
return None
def main():
lock = acquire_lock()
if not lock:
print("脚本已在运行,退出")
return
# 执行实际任务
try:
print("开始执行任务...")
time.sleep(30)
print("任务完成")
finally:
fcntl.flock(lock, fcntl.LOCK_UN)
lock.close()
try:
os.remove('/tmp/my_script.lock')
except:
pass
if __name__ == "__main__":
main()
PID文件方式
import os
import sys
import time
class SingleInstance:
def __init__(self, pid_file='/tmp/my_script.pid'):
self.pid_file = pid_file
def check_running(self):
if os.path.exists(self.pid_file):
try:
with open(self.pid_file, 'r') as f:
pid = int(f.read().strip())
# 检查进程是否存在
os.kill(pid, 0) # 信号0表示检查进程是否存在
return True
except (OSError, ValueError):
# 进程不存在或PID无效
pass
return False
def create_pid_file(self):
with open(self.pid_file, 'w') as f:
f.write(str(os.getpid()))
def remove_pid_file(self):
try:
os.remove(self.pid_file)
except:
pass
def __enter__(self):
if self.check_running():
sys.exit("脚本已在运行")
self.create_pid_file()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.remove_pid_file()
# 使用示例
def main():
with SingleInstance():
print("开始执行任务...")
time.sleep(30)
print("任务完成")
if __name__ == "__main__":
main()
使用atexit模块(更可靠)
import atexit
import os
import sys
import time
class SingleInstance:
def __init__(self, lock_file='/tmp/my_app.lock'):
self.lock_file = lock_file
self.fd = None
def acquire(self):
try:
self.fd = os.open(self.lock_file, os.O_CREAT | os.O_EXCL | os.O_RDWR)
return True
except FileExistsError:
return False
def release(self):
if self.fd:
os.close(self.fd)
try:
os.remove(self.lock_file)
except:
pass
# 全局单例
singleton = SingleInstance()
@atexit.register
def cleanup():
singleton.release()
def main():
if not singleton.acquire():
print("脚本已在运行,退出")
sys.exit(1)
print("开始执行任务...")
time.sleep(30)
print("任务完成")
if __name__ == "__main__":
main()
使用数据库/Redis锁(分布式场景)
import redis
import time
class RedisLock:
def __init__(self, redis_client, lock_key='my_task_lock', timeout=3600):
self.redis = redis_client
self.lock_key = lock_key
self.timeout = timeout
def acquire(self):
# 使用SET NX命令实现分布式锁
result = self.redis.setnx(self.lock_key, str(time.time()))
if result:
self.redis.expire(self.lock_key, self.timeout)
return True
return False
def release(self):
self.redis.delete(self.lock_key)
# 使用示例
def main():
r = redis.Redis(host='localhost', port=6379, db=0)
lock = RedisLock(r)
if not lock.acquire():
print("任务已在执行")
return
try:
print("开始执行任务...")
time.sleep(30)
print("任务完成")
finally:
lock.release()
if __name__ == "__main__":
main()
使用第三方库
filelock库(推荐)
pip install filelock
from filelock import FileLock
import time
def main():
lock = FileLock("/tmp/my_script.lock", timeout=0) # timeout=0 立即超时
try:
with lock.acquire():
print("开始执行任务...")
time.sleep(30)
print("任务完成")
except:
print("脚本已在运行,退出")
if __name__ == "__main__":
main()
使用Python内置的portalocker库
import portalocker
import time
def main():
lock_file = '/tmp/my_script.lock'
try:
with open(lock_file, 'w') as f:
portalocker.lock(f, portalocker.LOCK_EX | portalocker.LOCK_NB)
print("开始执行任务...")
time.sleep(30)
print("任务完成")
except portalocker.LockException:
print("脚本已在运行,退出")
if __name__ == "__main__":
main()
最佳实践建议
- 对于简单的单机部署:使用文件锁(flock/PID文件)即可
- 对于多进程/多线程:使用
filelock或portalocker库 - 对于分布式部署:使用Redis或数据库实现分布式锁
- 考虑异常情况:使用try-finally确保锁被释放
- 添加超时机制:防止死锁
选择哪种方案取决于你的具体场景和需求,对于大多数情况,使用filelock库是最简单可靠的选择。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播