프로그램의 인스턴스를 하나만 실행하는 Python 방식이 있습니까?
내가 생각해 낸 유일한 합리적인 해결책은 일부 포트에서 서버로 실행하려고 시도한 다음 동일한 포트에 바인딩하려는 두 번째 프로그램이 실패합니다. 하지만 정말 좋은 생각이 아닙니다. 아마도 이것보다 더 가벼운 것이 있을까요?
(프로그램이 때때로 실패 할 것으로 예상된다는 점을 고려하십시오. 즉, 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
import os
import sys
def instance_already_running(label="default"):
"""
Detect if an an instance with the label is already running, globally
at the operating system level.
Using `os.open` ensures that the file pointer won't be closed
by Python's garbage collector after the function's scope is exited.
The lock will be released when the program exits, or could be
released if the file pointer were closed.
"""
lock_file_pointer = os.open(f"/tmp/instance_{label}.lock", os.O_WRONLY)
try:
fcntl.lockf(lock_file_pointer, fcntl.LOCK_EX | fcntl.LOCK_NB)
already_running = False
except IOError:
already_running = True
return already_running
S.Lott의 제안과 매우 비슷하지만 코드가 있습니다.
답변
이 코드는 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
단일 인스턴스를 적용해야하는 여러 프로그램을 허용하도록 고유 문자열 을 변경할 수 있습니다.
답변
나는 그것이 충분히 파이썬인지 모르겠지만, 정의 된 포트에서 수신하는 Java 세계에서 모든 주요 플랫폼에서 작동하고 프로그램 충돌에 문제가 없기 때문에 꽤 널리 사용되는 솔루션입니다.
포트 수신의 또 다른 장점은 실행중인 인스턴스에 명령을 보낼 수 있다는 것입니다. 예를 들어 사용자가 프로그램을 두 번째로 시작하면 실행중인 인스턴스에 명령을 보내 다른 창을 열라는 명령을 보낼 수 있습니다 (예 : Firefox가 수행하는 작업입니다. TCP 포트 또는 명명 된 파이프를 사용하는지 또는 ‘그래도).
답변
전에는 파이썬을 작성하지 않았지만 이것은 crond에 의해 두 번 이상 시작되는 것을 방지하기 위해 mycheckpoint에서 방금 구현 한 것입니다.
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 uning에서 동일한 결과를 얻는 방법을 참조하십시오.