防止同时运行多个Python脚本实例

8

可能是重复问题:
Python: single instance of program

当作业运行时间超过启动间隔时,我需要防止cron作业并发运行。我尝试使用flock的概念来实现这一点,但fcntl模块的行为与我的预期不同。

有谁能告诉我为什么这可以防止两个并发实例:

import sys
import time
import fcntl

file_path = '/var/lock/test.py'
file_handle = open(file_path, 'w')

try:
    fcntl.lockf(file_handle, fcntl.LOCK_EX | fcntl.LOCK_NB)
    print 'no other instance is running'
    for i in range(5):
        time.sleep(1)
        print i + 1

except IOError:
    print 'another instance is running exiting now'
    sys.exit(0)

为什么这样不起作用:

import sys
import time
import fcntl

def file_is_locked(file_path):
    file_handle = open(file_path, 'w')
    try:
        fcntl.lockf(file_handle, fcntl.LOCK_EX | fcntl.LOCK_NB)
        return False
    except IOError:
        return True

file_path = '/var/lock/test.py'

if file_is_locked(file_path):
    print 'another instance is running exiting now'
    sys.exit(0)
else:
    print 'no other instance is running'
    for i in range(5):
        time.sleep(1)
        print i + 1

1
可能是重复的问题,与https://dev59.com/THRC5IYBdhLWcg3wMeBS相似。它也产生了一个名为[tendo](http://pypi.python.org/pypi/tendo)的库来处理所有烦人的跨平台问题。当然,它并没有回答“A为什么可以工作而B不行?”这个问题,但它确实解决了潜在的问题“我应该如何做?” - abarnert
4个回答

8

我的个人看法(虽然可能是完全错误的)是,file_handle 在函数中是局部变量(在第二种情况下),因此一旦函数完成,它就会被销毁。

下面的代码似乎按预期工作:

#!/usr/bin/env python
#https://dev59.com/Tm3Xa4cB1Zd3GeqPeGQp

import sys
import time
import fcntl

file_handle = None

def file_is_locked(file_path):
    global file_handle 
    file_handle= open(file_path, 'w')
    try:
        fcntl.lockf(file_handle, fcntl.LOCK_EX | fcntl.LOCK_NB)
        return False
    except IOError:
        return True

file_path = '/var/lock/test.py'

if file_is_locked(file_path):
    print 'another instance is running exiting now'
    sys.exit(0)
else:
    print 'no other instance is running'
    for i in range(5):
        time.sleep(1)
        print i + 1

请注意,我所做的唯一一件事就是将file_handle设置为全局变量(尽管我复制了整个代码以便有一个可工作的示例)


好的发现。问题在于在第一个实例完成运行之前,句柄被垃圾回收了,因此释放锁定,即使它尚未完成。看起来使用对象是个不错的理由。然后你可以使用相同的代码防止任意数量的循环、线程或进程并发运行。不过,你也可以尝试访问https://dev59.com/vXE85IYBdhLWcg3wYigB。 - Silas Ray

0
正如我在@BorrajaX的回答中提到的那样,由于看起来您已经受限于POSIX,因此您可以尝试使用本地命名信号量

0

-1

最简单的方法是在脚本开始时创建一个名为 /tmp/scriptlock 的文件,并在执行工作之前检查该文件是否存在。但请确保在处理结束时删除锁定文件。


如果您这样做,请确保使用Python的tempfile模块以避免竞态条件。 - limscoder
2
这与原帖中所做的几乎相同,他提出的问题是:“为什么它们不同?”而不是“我该如何做到这一点?” - Silas Ray
我愿意尝试其他避免竞态条件的方法,即使它们不使用fcntl。 - tponthieux

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接