当前位置:  开发笔记 > 编程语言 > 正文

确保只运行一个程序实例

如何解决《确保只运行一个程序实例》经验,为你挑选了8个好方法。

是否有Pythonic方法只运行一个程序实例?

我提出的唯一合理的解决方案是尝试在某个端口上将其作为服务器运行,然后第二个程序尝试绑定到同一个端口 - 失败.但这不是一个好主意,也许有比这更轻巧的东西?

(考虑到程序有时会失败,即段错误 - 所以像"锁定文件"这样的东西不起作用)

更新:提供的解决方案比仅存在一个不存在的服务器的端口要复杂得多且不太依赖,所以我必须使用那个.



1> sorin..:

以下代码应该完成这项工作,它是跨平台的,可以在Python 2.4-3.2上运行.我在Windows,OS X和Linux上测试过它.

from tendo import singleton
me = singleton.SingleInstance() # will sys.exit(-1) if other instance is running

最新的代码版本是singleton.py.请在这里提交错误.

您可以使用以下方法之一安装tend:

easy_install tendo

pip install tendo

从http://pypi.python.org/pypi/tendo手动获取它


对于像这样微不足道的东西的另一个依赖?听起来不是很吸引人.
我更新了答案,并附上了最新版本的链接.如果您发现了错误,请将其提交给github,我会尽快解决.
在Python 2.6下,这种语法对我不起作用.对我有用的是:1:来自tendo import singleton 2:me = singleton.SingleInstance()
单例是否处理获得sigterm的进程(例如,如果进程运行时间过长),还是必须处理?

2> Slava V..:

简单,跨平台的解决方案,在发现了另一个问题由Zgoda酒店:

import fcntl, sys
pid_file = 'program.pid'
fp = open(pid_file, 'w')
try:
    fcntl.lockf(fp, fcntl.LOCK_EX | fcntl.LOCK_NB)
except IOError:
    # another instance is running
    sys.exit(0)

很像S.Lott的建议,但有代码.


提示:如果要将其包装在函数'fp'中,则必须是全局的,否则文件将在函数退出后关闭.

3> Roberto Rosa..:

此代码特定于Linux.它使用"抽象"UNIX域套接字,但它很简单,不会留下陈旧的锁定文件.我更喜欢上面的解决方案,因为它不需要专门保留的TCP端口.

try:
    import socket
    s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
    ## Create an abstract socket, by prefixing it with null. 
    s.bind( '\0postconnect_gateway_notify_lock') 
except socket.error as e:
    error_code = e.args[0]
    error_string = e.args[1]
    print "Process already running (%d:%s ). Exiting" % ( error_code, error_string) 
    sys.exit (0) 

postconnect_gateway_notify_lock可以更改唯一字符串以允许需要强制执行单个实例的多个程序.


如上所述,此解决方案适用于Linux,但*不适用于Mac OS X.
此解决方案不起作用.我在Ubuntu 14.04上尝试过它.同时从2个终端窗口运行相同的脚本.他们都跑得很好.

4> Joachim Saue..:

我不知道它是否足够pythonic,但在Java世界中,侦听已定义的端口是一个非常广泛使用的解决方案,因为它适用于所有主要平台,并且没有任何崩溃程序的问题.

侦听端口的另一个好处是可以向正在运行的实例发送命令.例如,当用户第二次启动程序时,您可以向正在运行的实例发送一个命令,告诉它打开另一个窗口(例如,这就是Firefox所做的.我不知道他们是否使用TCP端口或命名管道或类似的东西,'虽然).



5> 小智..:

从来没有写过python,但这是我刚刚在mycheckpoint中实现的,以防止它被crond启动两次或更多次:

import os
import sys
import fcntl
fh=0
def run_once():
    global fh
    fh=open(os.path.realpath(__file__),'r')
    try:
        fcntl.flock(fh,fcntl.LOCK_EX|fcntl.LOCK_NB)
    except:
        os._exit(0)

run_once()

在另一期(http://stackoverflow.com/questions/2959474)中发布此事后,发现了Slava-N的建议.这个被称为函数,锁定执行脚本文件(不是pid文件)并保持锁定直到脚本结束(正常或错误).



6> Charlie Mart..:

使用pid文件.你有一些已知的位置,"/ path/to/pidfile",在启动时你会做这样的事情(部分伪代码,因为我是预先咖啡,不想那么努力):

import os, os.path
pidfilePath = """/path/to/pidfile"""
if os.path.exists(pidfilePath):
   pidfile = open(pidfilePath,"r")
   pidString = pidfile.read()
   if :
      # something is real weird
      Sys.exit(BADCODE)
   else:
      
      if  :
          Sys.exit(ALREADAYRUNNING)
      else:
          # the previous server must have crashed
          
          
          pidfile.write(os.getpid())
else:
    
    pidfile.write(os.getpid())

所以,换句话说,你正在检查是否存在pid文件; 如果没有,请将您的pid写入该文件.如果pidfile确实存在,那么检查pid是否是正在运行的进程的pid; 如果是这样,那么你有另一个正在运行的进程,所以只需关闭.如果没有,那么前一个进程崩溃,所以记录它,然后将自己的pid写入文件而不是旧文件.然后继续.


这有比赛条件。测试然后写入序列可能会引发两个程序几乎同时启动,找不到文件并尝试同时打开以进行写入的异常。它*应该*在其中一个上引发例外,允许另一个继续进行。

7> zgoda..:

您已经在另一个线程中找到了对类似问题的回复,因此为了完整起见,请参阅如何在Windows上实现相同的名为mutex.

http://code.activestate.com/recipes/474070/



8> S.Lott..:

这可能有效。

    尝试将PID文件创建到已知位置。如果失败,则有人将文件锁定了,您就完成了。

    正常完成后,请关闭并删除PID文件,以便其他人可以覆盖它。

您可以将程序包装在Shell脚本中,即使程序崩溃,该脚本也会删除PID文件。

如果程序挂起,也可以使用PID文件将其杀死。

推荐阅读
LEEstarmmmmm
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有