6

我正在写一个Python 2.7脚本。
总之,这个脚本每晚都在运行Linux并激活几个进程。

我想确保此脚本不会并行运行多次(基本上是在尝试模仿Singleton模式,但在应用程序级别)。

代码示例

def main():
    # before doing anything, I'd like to know whether this
    # script was activated and alive. 
    # if so, error out

    # do something

if __name__ == "__main__":
    main()

建议

天真的解决方案是创建某种锁定文件,充当互斥锁。
我们要做的第一件事就是检查这个文件是否存在。如果是这样,那么脚本的其他实例已经创建了它,我们应该出错。脚本完成后,我们删除此文件。
我假设这个解决方案可以工作,只要文件系统上的操作是原子的。

执行

import os, sys

lock_file_path = ".lock_script"

def lock_mutex():
    if os.path.exists(lock_mutex_path):
        print "Error: script was already activated."
        sys.exit(-1)

    else:
        file = open(lock_mutex_path, 'w')

def unlock_mutex():
    assert( os.path.exists(lock_mutex_path))
    os.remove(lock_mutex_path)

def main():

    try:
        lock_mutex()

        # do something

        unlock_mutex()

    except:
        unlock_mutex()

if __name__ == "__main__":
    main()

问题

如何保证lock_mutex()unlock_mutex()是原子的?

4

2 回答 2

5

由于您使用的是 linux,因此您可以使用flock

import os
import fcntl
import time

def main():
  # acquire the prog lock
  if not prog_lock_acq('singleton.lock'):
    print("another instance is running")
    exit(1)

  print("program is running-press Ctrl+C to stop")
  while True:
    time.sleep(10)

def prog_lock_acq(lpath):
  fd = None
  try:
    fd = os.open(lpath, os.O_CREAT)
    fcntl.flock(fd, fcntl.LOCK_NB | fcntl.LOCK_EX)
    return True
  except (OSError, IOError):
    if fd: os.close(fd)
    return False

if __name__ == '__main__':
  main()

退出后我们让文件保持打开并不重要,prog_lock_acq因为当进程退出时,它会被操作系统自动关闭。此外,如果您省略LOCK_NB选项,flock调用将阻塞,直到当前正在运行的进程退出。根据您的用例,这可能很有用。

请注意,我们不会在退出时删除文件。没关系。文件的存在并不表示一个活动的进程——锁是。所以即使你用 杀死你的进程kill -9,锁仍然被释放。

但是有一个警告:如果您在进程运行时取消锁定文件的链接,当进程的下一个实例运行时,它将创建一个新文件,该文件将没有锁定并且运行良好,这将违反我们的单例设计。您可能可以对目录做一些聪明的事情来防止取消链接,但我不确定这会有多强大。

于 2013-11-03T12:32:34.933 回答
1

我使用主管(http://supervisord.org/)在 Linux 下运行东西。它运行 Django、Celeryd 等,并确保它们在意外完成时重新启动。

但也可以设置选项,使命令在完成时不会自动启动或重新启动:autostart=false、autorestart=false、starseconds=0。我将它用于这些 cron 作业。

在 cron 中,我输入了命令“supervisorctl start myscript”,如果 myscript 已经在 supervisor 下运行,它什么也不做,否则启动它。

无论脚本是用什么语言编写的,都能完美运行。

于 2013-11-03T12:44:19.753 回答