2010-05-29 2 views
10

동일한 장기 실행 python 명령 줄 스크립트의 여러 인스턴스가 동시에 실행되는 것을 방지하려면 새 인스턴스가 원래 인스턴스로 데이터를 보낼 수 있도록 새 인스턴스를 보내고 싶습니다. 자살을 저지른다. 크로스 플랫폼 방식으로이 작업을 수행하려면 어떻게해야합니까?파이썬 스크립트는 동일한 스크립트의 다른 인스턴스가 실행 중임을 알 수 있습니까?

특히, 나는 다음과 같은 동작 사용하려는 :

  1. "foo.py은"명령 줄에서 시작되어, 그것은 기계가 될 때까지 긴으로 .. 일 또는 몇 주 동안 실행 남아있을 것입니다 재부팅되거나 상위 프로세스가이를 종료합니다.
  2. 같은 스크립트가 다시 시작되지만 실행될 때 다른 명령 줄 매개 변수가
  3. 인 경우 스크립트는 다른 인스턴스가 실행 중인지 확인해야합니다.
  4. 다른 인스턴스가 실행중인 경우 인스턴스 # 2는 인스턴스 # 1에 명령 줄 매개 변수를 보내야하고 인스턴스 # 2는 종료되어야합니다.
  5. 인스턴스 # 1은 다른 스크립트에서 명령 줄 매개 변수를 받으면 새 스레드를 시작하고 (위의 단계에서 보낸 명령 줄 매개 변수를 사용하여) 인스턴스 # 2가 수행 할 작업을 수행하기 시작해야합니다 .

그래서 저는 두 가지를 찾고 있습니다 : 어떻게 파이썬 프로그램이 자체의 다른 인스턴스가 실행되고 있는지 그리고 어떻게 파이썬 명령 행 프로그램이 다른 것과 통신 할 수 있습니까?

이 스크립트를 더 복잡하게 만드는 것은 Windows와 Linux 모두에서 동일한 스크립트를 실행해야하므로 이상적으로 솔루션은 OS 특정 호출이 아닌 Python 표준 라이브러리 만 사용하는 것이 이상적입니다. Windows codepath와 * nix codepath (그리고 내 코드에서 큰 코드 if) 중 하나를 선택해야하는 경우에는 "동일한 코드"솔루션을 사용할 수 없다면 괜찮습니다.

필자는 파일 기반 접근법 (예 : 인스턴스 # 1이 변경 사항을 감시하고 각 인스턴스가 작업을 수행하려고 할 때 해당 디렉토리에 파일을 놓는 등)을 해결할 수 있음을 알고 있지만 약간 걱정이됩니다. 비 정상적인 시스템 종료 후 해당 파일을 정리합니다. 이상적으로는 메모리 내 솔루션을 사용할 수 있습니다. 그러나 다시 말하지만 융통성이 있습니다. 파일 기반의 영구적 인 접근 만이이를 수행 할 수있는 유일한 방법이라면, 나는 그 옵션에 개방적입니다.

추가 정보 : 우리 서버가 모니터링 도구 (예 : 데이터베이스 쿼리 또는 웹 서비스 호출 결과)를 수집하기 위해 파이썬 스크립트를 실행하는 모니터링 도구를 사용하고 있기 때문에이 작업을 수행하려고합니다. 나중에 사용하십시오. 이 스크립트 중 일부는 시작하는 데 비용이 많이 들지만 시작 후 실행하기가 저렴합니다 (예 : DB 연결 만들기와 쿼리 실행). 그래서 우리는 부모 프로세스가 그들을 죽일 때까지 무한 루프에서 실행되도록 선택했습니다.

위대한 작품이지만 큰 서버에서는 각각 20 분마다 데이터를 수집하는 경우에도 동일한 스크립트의 인스턴스가 100 개 실행될 수 있습니다. 이것은 RAM, DB 연결 제한 등으로 큰 혼란을 야기합니다. 우리는 하나의 스레드가있는 100 개의 프로세스에서 100 개의 스레드로 하나의 프로세스로 전환하려고합니다. 각 스레드는 이전에 하나의 스크립트가 수행하고 있던 작업을 실행합니다.

그러나 모니터링 도구로 스크립트를 호출하는 방법을 변경하는 것은 불가능합니다. 우리는 호출을 동일하게 유지하고 (다른 명령 행 매개 변수로 프로세스를 시작) 스크립트를 변경하여 다른 스크립트가 활성 상태임을 인식하고 "new"스크립트가 명령 행 매개 변수의 작업 지시를 보내도록합니다. "old"스크립트에 추가하십시오.

나는이 스크립트를 원 스크립트로하고 싶지 않습니다. 대신이 동작을 많은 스크립트 작성자가 활용할 수있는 라이브러리에 패키지화하려고합니다. 내 목표는 스크립트 작성자가 다중 인스턴스 문제를 인식하지 못하는 단순한 단일 스레드 스크립트를 작성하고 다중 스레드를 처리 할 수있게하는 것입니다 커버 아래 단일 인스 턴싱.

+0

작업 스크립트가 명령 호출 스크립트와 다른 이유는 무엇입니까? 작업자 스크립트는 모니터링 프레임 워크에서 호출 한 명령 릴레이 클라이언트가 보낸 명령을받는 서버 프로세스 일 수 있습니다.이 작업은 서버에게 수행 할 작업을 알려주는 작업입니다. – Bernd

답변

9

통신 채널을 설정하는 Alex Martelli의 접근 방식이 적절합니다. 원하는 경우 멀티 프로세싱 .connection.Listener를 사용하여 리스너를 만듭니다.

AF_INET (소켓) 대신 Linux 용 AF_UNIX 및 Windows 용 AF_PIPE를 사용할 수 있습니다. 바라건대 작은 "if"는 상처를주지 않을 것입니다.

편집 : 예를 들어 상처를 입지 않았을 것입니다. 그것은 기본적인 하나입니다.

#!/usr/bin/env python 

from multiprocessing.connection import Listener, Client 
import socket 
from array import array 
from sys import argv 

def myloop(address): 
    try: 
     listener = Listener(*address) 
     conn = listener.accept() 
     serve(conn) 
    except socket.error, e: 
     conn = Client(*address) 
     conn.send('this is a client') 
     conn.send('close') 

def serve(conn): 
    while True: 
     msg = conn.recv() 
     if msg.upper() == 'CLOSE': 
      break 
     print msg 
    conn.close() 

if __name__ == '__main__': 
    address = ('/tmp/testipc', 'AF_UNIX') 
    myloop(address) 

이것은 OS X에서 작동하므로 Linux와 (올바른 주소를 대체 한 후) Windows에서 테스트해야합니다. 보안 포인트에서 많은주의 사항이 존재합니다. 가장 중요한 점은 conn.recv가 데이터를 unpickle 처리하므로 recv_bytes를 사용하는 것이 좋습니다.

+0

좋은 답변입니다! 고유 한 스크립트 다음에 pipe/fifo의 이름을 지정할 수 있으므로 명명 된 파이프 (windows) 또는 fifo (unix)를 사용할 수 있으므로 스크립트와 포트 번호 사이의 매핑을 유지하는 것보다 훨씬 쉬워 보입니다. –

1

아마도 통신용 소켓을 사용해보십시오.

9

일반적인 접근법은 시작시에 스크립트가 독점적 인 방법으로 통신 채널을 설정하도록하는 것입니다 (동일한 채널을 설정하기위한 다른 시도가 예측 가능한 방식으로 실패 함). 스크립트가 첫 번째 실행을 감지 할 수 있습니다. 대화가 있습니다.

크로스 플랫폼 기능에 대한 요구 사항은 문제의 통신 채널로 소켓을 사용하는 것을 강력하게 나타냅니다. 스크립트에 예약 된 "잘 알려진 포트"를 지정할 수 있습니다 (예 : 12345). 해당 포트에서 소켓 열기 로컬 호스트에만 (127.0.0.1). 문제의 포트가 "가져 오기 (take)"되었기 때문에 해당 소켓을 열지 못하면 그 포트 번호에 대신 연결할 수 있습니다. 그러면 기존 스크립트와 통신 할 수 있습니다.

소켓 프로그래밍에 익숙하지 않다면 HOWTO 의사 here이 좋습니다. Python in a Nutshell에있는 관련 장을 볼 수도 있습니다 (나는 그 중 하나에 대해 편견이 있습니다 ;-).

+0

안녕하세요 알렉스 - 빠른 응답을 보내 주셔서 감사합니다! 잘 알려진 포트 접근법에 대한 나의 주요 관심사는 갈등 (서버를 소유하지 않기 때문에 다른 프로그램에서 해당 포트를 사용할 수 있음)과 포트 번호 관리 (단일 인스턴스 트릭 다른 스크립트 작성자가 유지 관리하는 많은 스크립트). 위의 문제를 해결할 수있는 방법이 있습니까? 아니면 "명명 된 IPC"메커니즘으로 더 나아질 수 있습니까? * nix의 Windows 소켓과 도메인 소켓이이 작업을 수행 할 수 있다고 생각하지만 Python에서 사용하는 것이 얼마나 쉬운 지 알지 못합니다. –

+0

@ Justin, 크로스 플랫폼 및 "본질적으로 상호 배타적 인"방식으로 명명 된 파이프 및 유닉스 도메인 소켓과 같은 메커니즘을 어떻게 사용할지 모르겠습니다. 당신이 식별 할 수있는 특정 요구 사항을 지원하기 위해서, 이름을 유지하는'.dbm' (또는 sqlite 등) 아카이브에 접근하고 업데이트함으로써 이름 X의 스크립트가 사용되어야하는 "잘 알려지지 않은 포트"를 기록 할 수 있습니다. 포트 통신 (시작시 스크립트가 거기에서 이름을 찾지 못하면 OS에서 새로운 포트를 가져 와서 기록합니다), 경쟁 조건을 피하기 위해 파일 잠금 메커니즘을 사용합니다. –

+0

@Muhammad Alkarouri의 답변 (다중 처리 패키지 사용)은 스크립트를 포트 번호에 매핑하는 복잡성을 피하면서 실행 가능한 교차 플랫폼 솔루션처럼 보입니다. '멀티 프로세싱 '사용의 단점은 무엇입니까? –

0

가장 좋은 방법은 pid 파일을 고수하면서 프로세스 ID를 포함시키는 것 뿐이지 만 이전 인스턴스가 수신하는 포트 번호도 포함해야합니다. 그래서 시작할 때 pid 파일을 확인하고 그 ID를 가진 프로세스가 실행 중인지 확인하십시오. 그렇다면 데이터를 보내고 종료하면 pid 파일을 현재 프로세스의 정보로 덮어 씁니다.

관련 문제