python - 确保脚本只激活一次

ida*_*hmu 6 python atomicity python-2.7

我正在写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()
Run Code Online (Sandbox Code Playgroud)

建议

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

履行

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()
Run Code Online (Sandbox Code Playgroud)

问题

如何确保lock_mutex()并且unlock_mutex()是原子的?

Man*_*our 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()
Run Code Online (Sandbox Code Playgroud)

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

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

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


Rem*_*ich 1

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

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

在 cron 中,我输入了命令“supervisorctl start myscript”,如果 myscript 已经在主管下运行,则该命令不执行任何操作,否则启动它。

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