프로그램의 단일 인스턴스 만 실행 중인지 확인하십시오
하나의 프로그램 인스턴스 만 실행하는 Pythonic 방법이 있습니까?
내가 찾은 합리적인 해결책은 일부 포트에서 서버로 실행하려고 시도한 다음 동일한 포트에 바인딩하려고하는 두 번째 프로그램이 실패하는 것입니다. 그러나 그것은 좋은 생각이 아닙니다. 아마도 이것보다 가벼운 것이 있습니까?
(프로그램이 때때로 실패 할 것이라는 점을 고려하십시오. 즉, segfault- "파일 잠금"과 같은 것은 작동하지 않습니다)
다음 코드는 작업을 수행해야하며 크로스 플랫폼이며 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 에서 수동으로 가져 와서
간단한, 크로스 플랫폼 솔루션에서 발견 된 또 다른 질문 으로 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의 제안과 비슷하지만 코드가 있습니다.
이 코드는 Linux 전용입니다. 'abstract'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
단일 인스턴스가 필요한 여러 프로그램을 허용하도록 고유 문자열 을 변경할 수 있습니다.
파이썬이 충분한 지 모르겠지만 Java 세계에서는 정의 된 포트에서 듣는 것이 모든 주요 플랫폼에서 작동하며 충돌 프로그램에 아무런 문제가 없으므로 매우 널리 사용되는 솔루션입니다.
포트 청취의 또 다른 장점은 실행중인 인스턴스에 명령을 보낼 수 있다는 것입니다. 예를 들어 사용자가 프로그램을 두 번 시작할 때 실행중인 인스턴스에 다른 창을 열도록 명령을 보낼 수 있습니다 (예 : Firefox의 기능). TCP 포트 또는 명명 된 파이프를 사용하는지 또는 그런 식으로 말하지만
전에는 파이썬을 쓰지 않았지만, 이것이 내 체크 포인트에서 방금 구현 한 것입니다. 크론으로 두 번 이상 시작되지 않도록합니다.
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 파일 아님)을 잠그고 스크립트가 끝날 때까지 (정상 또는 오류) 잠금을 유지합니다.
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 <pidString is equal to os.getpid()>:
# something is real weird
Sys.exit(BADCODE)
else:
<use ps or pidof to see if the process with pid pidString is still running>
if <process with pid == 'pidString' is still running>:
Sys.exit(ALREADAYRUNNING)
else:
# the previous server must have crashed
<log server had crashed>
<reopen pidfilePath for writing>
pidfile.write(os.getpid())
else:
<open pidfilePath for writing>
pidfile.write(os.getpid())
다시 말해, pidfile이 존재하는지 확인하는 것입니다. 그렇지 않으면 pid를 해당 파일에 작성하십시오. pidfile이 존재하면 pid가 실행중인 프로세스의 pid인지 확인하십시오. 그렇다면 다른 라이브 프로세스가 실행 중이므로 종료하십시오. 그렇지 않은 경우 이전 프로세스가 중단되었으므로 기록한 다음 이전 프로세스 대신 자신의 pid를 파일에 씁니다. 그런 다음 계속하십시오.
이미 다른 스레드에서 비슷한 질문에 대한 답변을 찾았으므로 완전성을 위해 Windows에서 명명 된 뮤텍스에서 동일한 결과를 얻는 방법을 참조하십시오.
http://code.activestate.com/recipes/474070/
작동 할 수 있습니다.
알려진 위치에 PID 파일을 작성하십시오. 실패하면 누군가 파일을 잠갔습니다.
정상적으로 완료되면 다른 사람이 덮어 쓸 수 있도록 PID 파일을 닫고 제거하십시오.
프로그램이 충돌하더라도 PID 파일을 제거하는 쉘 스크립트로 프로그램을 랩핑 할 수 있습니다.
또한 PID 파일을 사용하여 프로그램이 중단 된 경우 프로그램을 종료 할 수 있습니다.
잠금 파일을 사용하는 것은 유닉스에서 매우 일반적인 접근 방식입니다. 충돌이 발생하면 수동으로 정리해야합니다. 파일에 PID를 저장하고 시작시이 PID에 대한 프로세스가 있는지 확인하고 잠금 파일을 무시합니다. 그러나 read-file-check-pid-rewrite-file을 잠그는 것도 필요합니다. os- package 에서 pid를 가져오고 확인하는 데 필요한 것을 찾을 수 있습니다 . 주어진 pid를 가진 프로세스가 있는지 확인하는 일반적인 방법은 치명적이지 않은 신호를 보내는 것입니다.
다른 대안은 이것을 무리 또는 posix 세마포어와 결합 할 수 있습니다.
saua가 제안한 것처럼 네트워크 소켓을 여는 것이 아마도 가장 쉽고 이식성이 좋을 것입니다.
사용하는 사람의 경우 wxPython을을 자신의 응용 프로그램을 위해, 당신은 기능을 사용할 수 있습니다 wx.SingleInstanceChecker
여기에 기록을 .
나는 개인적으로 서브 클래스 사용 wx.App
의 사용을 만드는 wx.SingleInstanceChecker
되돌아 False
에서 OnInit()
응용 프로그램이 이미 같은 실행의 기존 인스턴스가있는 경우를 :
import wx
class SingleApp(wx.App):
"""
class that extends wx.App and only permits a single running instance.
"""
def OnInit(self):
"""
wx.App init function that returns False if the app is already running.
"""
self.name = "SingleApp-%s".format(wx.GetUserId())
self.instance = wx.SingleInstanceChecker(self.name)
if self.instance.IsAnotherRunning():
wx.MessageBox(
"An instance of the application is already running",
"Error",
wx.OK | wx.ICON_WARNING
)
return False
return True
이것은 wx.App
여러 인스턴스를 금지 하는 간단한 드롭 인 대체입니다 . 단순히 대체 사용 wx.App
으로 SingleApp
다음처럼 코드 :
app = SingleApp(redirect=False)
frame = wx.Frame(None, wx.ID_ANY, "Hello World")
frame.Show(True)
app.MainLoop()
다음은 최종 Windows 전용 솔루션입니다. 다음을 아마도 'onlyone.py'또는 무엇이든 모듈에 넣습니다. 해당 모듈을 __ 기본 __ 파이썬 스크립트 파일에 직접 포함하십시오.
import win32event, win32api, winerror, time, sys, os
main_path = os.path.abspath(sys.modules['__main__'].__file__).replace("\\", "/")
first = True
while True:
mutex = win32event.CreateMutex(None, False, main_path + "_{<paste YOUR GUID HERE>}")
if win32api.GetLastError() == 0:
break
win32api.CloseHandle(mutex)
if first:
print "Another instance of %s running, please wait for completion" % main_path
first = False
time.sleep(1)
설명
코드는 스크립트의 전체 경로에서 파생 된 이름으로 뮤텍스를 만들려고 시도합니다. 실제 파일 시스템과의 혼동을 피하기 위해 슬래시를 사용합니다.
장점
- 구성 또는 '매직'식별자가 필요하지 않으므로 필요한만큼 다른 스크립트에서 사용하십시오.
- No stale files left around, the mutex dies with you.
- Prints a helpful message when waiting
The best solution for this on windows is to use mutexes as suggested by @zgoda.
import win32event
import win32api
from winerror import ERROR_ALREADY_EXISTS
mutex = win32event.CreateMutex(None, False, 'name')
last_error = win32api.GetLastError()
if last_error == ERROR_ALREADY_EXISTS:
print("App instance already running")
Some answers use fctnl
(included also in @sorin tendo package) which is not available on windows and should you try to freeze your python app using a package like pyinstaller
which does static imports, it throws an error.
Also, using the lock file method, creates a read-only
problem with database files( experienced this with sqlite3
).
I'm posting this as an answer because I'm a new user and Stack Overflow won't let me vote yet.
Sorin Sbarnea's solution works for me under OS X, Linux and Windows, and I am grateful for it.
However, tempfile.gettempdir() behaves one way under OS X and Windows and another under other some/many/all(?) *nixes (ignoring the fact that OS X is also Unix!). The difference is important to this code.
OS X and Windows have user-specific temp directories, so a tempfile created by one user isn't visible to another user. By contrast, under many versions of *nix (I tested Ubuntu 9, RHEL 5, OpenSolaris 2008 and FreeBSD 8), the temp dir is /tmp for all users.
That means that when the lockfile is created on a multi-user machine, it's created in /tmp and only the user who creates the lockfile the first time will be able to run the application.
A possible solution is to embed the current username in the name of the lock file.
It's worth noting that the OP's solution of grabbing a port will also misbehave on a multi-user machine.
I use single_process
on my gentoo;
pip install single_process
example:
from single_process import single_process
@single_process
def main():
print 1
if __name__ == "__main__":
main()
refer: https://pypi.python.org/pypi/single_process/1.0
I keep suspecting there ought to be a good POSIXy solution using process groups, without having to hit the file system, but I can't quite nail it down. Something like:
On startup, your process sends a 'kill -0' to all processes in a particular group. If any such processes exist, it exits. Then it joins the group. No other processes use that group.
However, this has a race condition - multiple processes could all do this at precisely the same time and all end up joining the group and running simultaneously. By the time you've added some sort of mutex to make it watertight, you no longer need the process groups.
This might be acceptable if your process only gets started by cron, once every minute or every hour, but it makes me a bit nervous that it would go wrong precisely on the day when you don't want it to.
I guess this isn't a very good solution after all, unless someone can improve on it?
I ran into this exact problem last week, and although I did find some good solutions, I decided to make a very simple and clean python package and uploaded it to PyPI. It differs from tendo in that it can lock any string resource name. Although you could certainly lock __file__
to achieve the same effect.
Install with: pip install quicklock
Using it is extremely simple:
[nate@Nates-MacBook-Pro-3 ~/live] python
Python 2.7.6 (default, Sep 9 2014, 15:04:36)
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.39)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from quicklock import singleton
>>> # Let's create a lock so that only one instance of a script will run
...
>>> singleton('hello world')
>>>
>>> # Let's try to do that again, this should fail
...
>>> singleton('hello world')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/nate/live/gallery/env/lib/python2.7/site-packages/quicklock/quicklock.py", line 47, in singleton
raise RuntimeError('Resource <{}> is currently locked by <Process {}: "{}">'.format(resource, other_process.pid, other_process.name()))
RuntimeError: Resource <hello world> is currently locked by <Process 24801: "python">
>>>
>>> # But if we quit this process, we release the lock automatically
...
>>> ^D
[nate@Nates-MacBook-Pro-3 ~/live] python
Python 2.7.6 (default, Sep 9 2014, 15:04:36)
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.39)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from quicklock import singleton
>>> singleton('hello world')
>>>
>>> # No exception was thrown, we own 'hello world'!
Take a look: https://pypi.python.org/pypi/quicklock
linux example
This method is based on the creation of a temporary file automatically deleted after you close the application. the program launch we verify the existence of the file; if the file exists ( there is a pending execution) , the program is closed ; otherwise it creates the file and continues the execution of the program.
from tempfile import *
import time
import os
import sys
f = NamedTemporaryFile( prefix='lock01_', delete=True) if not [f for f in os.listdir('/tmp') if f.find('lock01_')!=-1] else sys.exit()
YOUR CODE COMES HERE
On a Linux system one could also ask pgrep -a
for the number of instances, the script is found in the process list (option -a reveals the full command line string). E.g.
import os
import sys
import subprocess
procOut = subprocess.check_output( "/bin/pgrep -u $UID -a python", shell=True,
executable="/bin/bash", universal_newlines=True)
if procOut.count( os.path.basename(__file__)) > 1 :
sys.exit( ("found another instance of >{}<, quitting."
).format( os.path.basename(__file__)))
Remove -u $UID
if the restriction should apply to all users. Disclaimer: a) it is assumed that the script's (base)name is unique, b) there might be race conditions.
import sys,os
# start program
try: # (1)
os.unlink('lock') # (2)
fd=os.open("lock", os.O_CREAT|os.O_EXCL) # (3)
except:
try: fd=os.open("lock", os.O_CREAT|os.O_EXCL) # (4)
except:
print "Another Program running !.." # (5)
sys.exit()
# your program ...
# ...
# exit program
try: os.close(fd) # (6)
except: pass
try: os.unlink('lock')
except: pass
sys.exit()
참고URL : https://stackoverflow.com/questions/380870/make-sure-only-a-single-instance-of-a-program-is-running
'development' 카테고리의 다른 글
RGB 값이 주어지면 색조 (또는 음영)를 어떻게 만듭니 까? (0) | 2020.07.29 |
---|---|
Bootstrap 4의 '.well'에 해당하는 클래스는 무엇입니까 (0) | 2020.07.29 |
스트림이란? (0) | 2020.07.29 |
파이썬 매개 변수 대 URL 매개 변수 (0) | 2020.07.29 |
에 이미지 삽입 (0) | 2020.07.29 |