2010-05-23 3 views
3

나는 외부 프로세스를 관리해야하는 GUI 애플리케이션을 작업 해왔다. 외부 프로세스로 작업하면 프로그래머의 삶을 어렵게 만드는 많은 문제가 발생합니다. 이 앱의 유지 관리가 오래도록 받아 들일 수없는 것 같습니다. 나는 외부 프로세스로 작업하는 것을 어렵게 만들었 기 때문에 고통을 완화 할 수있는 방법을 찾아 낼 수있었습니다. 이런 종류의 호언 장담은 내가 약간의 피드백을 얻고이 매우 어두운 바다로 항해하는 것을 생각하는 누군가에게 약간의 지침을 제공하기 위해 여기에 게시 할 것이라고 생각한 호언 장담으로 바뀌었다. 여기에 내가 지금까지 무엇을 가지고있어 :외부 프로세스 다루기

  1. 출력 결과가 상위와 섞일 수 있습니다. 이로 인해 두 가지 출력 모두를 오도하기 쉽고 읽기가 어려울 수 있습니다. 어디서 왔는지 알기가 어려울 수 있습니다. 상황이 비동기 일 때 어떤 일이 일어나는지 파악하는 것이 더 어려워집니다. 여기에 인위적인 예입니다 :

    import textwrap, os, time 
    from subprocess import Popen 
    test_path = 'test_file.py' 
    
    with open(test_path, 'w') as file: 
        file.write(textwrap.dedent(''' 
         import time 
         for i in range(3): 
          print 'Hello %i' % i 
          time.sleep(1)''')) 
    
    proc = Popen('python -B "%s"' % test_path) 
    
    for i in range(3): 
        print 'Hello %i' % i 
        time.sleep(1) 
    
    os.remove(test_path) 
    

    출력 :

    Hello 0 
    Hello 0 
    Hello 1 
    Hello 1 
    Hello 2 
    Hello 2 
    

    내가 자식 프로세스가 파일로 출력을 쓰기가있을 것 같아요. 그러나 인쇄문의 결과를보고 싶을 때마다 파일을 열어야하는 것은 귀찮을 수 있습니다.

    자식 프로세스 용 코드가있는 경우 print 'child: Hello %i'과 같은 레이블을 추가 할 수 있지만 인쇄 할 때마다 성가신 일이 발생할 수 있습니다. 그리고 출력에 약간의 노이즈가 추가됩니다. 물론 코드에 액세스 할 수 없다면 나는 그것을 할 수 없습니다.

    프로세스 출력을 수동으로 관리 할 수 ​​있습니다. 하지만 그런 다음 스레드와 폴링 등의 웜으로 엄청난 양의 웜을 열 수 있습니다.

    간단한 해결책은 동기 함수와 같은 프로세스를 처리하는 것입니다. 즉, 프로세스가 완료 될 때까지 더 이상 코드를 실행하지 않아야합니다. 즉, 프로세스 블록을 만드십시오. 하지만 GUI 응용 프로그램을 만드는 경우에는 작동하지 않습니다. 어느 것이 나를 다음 문제로 인도합니까?

  2. 차단 프로세스로 인해 gui가 응답하지 않게됩니다.

    import textwrap, sys, os 
    from subprocess import Popen 
    
    from PyQt4.QtGui import * 
    from PyQt4.QtCore import * 
    
    test_path = 'test_file.py' 
    with open(test_path, 'w') as file: 
        file.write(textwrap.dedent(''' 
         import time 
         for i in range(3): 
          print 'Hello %i' % i 
          time.sleep(1)''')) 
    
    app = QApplication(sys.argv) 
    button = QPushButton('Launch process') 
    def launch_proc(): 
        # Can't move the window until process completes 
        proc = Popen('python -B "%s"' % test_path) 
        proc.communicate() 
    button.connect(button, SIGNAL('clicked()'), launch_proc) 
    button.show() 
    app.exec_() 
    os.remove(test_path) 
    

    는 Qt는이 작업에 도움을 줄 수 있습니다 QProcess라고 자신의 프로세스 래퍼를 제공합니다. 함수를 신호에 연결하여 상대적으로 쉽게 출력을 캡처 할 수 있습니다. 이것이 내가 현재 사용하고있는 것입니다. 그러나 나는이 모든 신호가 goto 진술과 같이 의심스럽게 행동하고 스파게티 코드로 이어질 수 있음을 알고 있습니다. Qopcess에서 'finished'신호를 보내 프로세스 호출 후에 오는 모든 코드를 포함하는 함수를 호출함으로써 일종의 블로킹 동작을 얻고 싶습니다. 그게 효과가 있다고 생각하지만 세부 사항에 대해서는 아직 약간 애매합니다. ...

  3. 하위 프로세스에서 상위 프로세스로 이동하면 스택 추적이 중단됩니다. 정상적인 기능이 실패하면 파일 이름과 행 번호가 포함 된 완전한 스택 추적을 얻게됩니다. 서브 프로세스가 망가져 버리면 결과가 나오면 운이 좋을 것입니다. 무언가가 잘못 될 때마다 더 많은 형사 작업을해야만합니다.

  4. 말하자면, 출력은 외부 프로세스를 처리 할 때 사라지는 방식입니다. 마치 창 'cmd'명령을 통해 무언가를 실행하는 것처럼 콘솔은 팝업을 실행하고 코드를 실행 한 다음 출력을 볼 수있는 기회를 갖기 전에 사라집니다. #/k 플래그를 건네 주어야합니다. 비슷한 문제가 항상 생겨난 것 같습니다.

    문제 3과 4가 모두 근본 원인이 같다고 가정합니다. 예외 처리가 없습니다. 예외 처리는 함수와 함께 사용하기위한 것이지 프로세스와는 작동하지 않습니다. 프로세스에 대한 예외 처리와 같은 것을 얻을 수있는 방법이 있습니까? 그게 stderr에 대한 것 같아요? 그러나 두 가지 스트림을 다루는 것은 그 자체로 성가심 일 수 있습니다. 어쩌면 나는이 부분을 조사해야 할 것입니다 ...

  5. 프로세스가 깨닫지 못하고 백그라운드에서 멈추거나 깨닫지 못합니다. 그래서 당신은 당신의 컴퓨터에 고함 소리를 내며 결국 당신의 작업 관리자를 가져올 때까지 천천히 진행될 것이고 동일한 프로세스의 30 개의 인스턴스가 백그라운드에서 나가는 것을 보게 될 것입니다.

    또한 걸려있는 백그라운드 프로세스는 파일에 대한 핸들을 잡거나 권한을 부여하여 권한 오류를 일으키는 등 다양한 재미있는 방식으로 프로세스의 다른 인스턴스와 간섭 할 수 있습니다.

    자식 프로세스가 닫히지 않으면 부모 프로세스가 자식 프로세스를 종료 할 수있는 것이 쉬운 해결책 인 것 같습니다. 그러나 부모 프로세스가 충돌하면 정리 코드가 호출되지 않고 자식이 중단 될 수 있습니다.

    또한 부모가 자식이 완료 될 때까지 기다렸다가 자식이 무한 루프 또는 무언가에 있으면 두 개의 정지 프로세스가 발생할 수 있습니다.

    이 문제는 재미를 위해 문제 2와 관련되어있어 GUI가 완전히 응답하지 않고 작업 관리자로 모든 것을 강제 종료 할 수 있습니다.

  6. F는 *** ING는

    매개 변수는 종종 프로세스에 전달 될 필요가 인용한다. 이것은 그 자체로 두통입니다. 특히 파일 경로를 다루는 경우. 'C :/My Documents/whatever /'라고 말하면됩니다. 따옴표가 없으면 문자열은 종종 공간에서 분리되어 두 개의 인수로 해석됩니다. 중첩 된 따옴표가 필요하다면 'and'를 사용할 수 있습니다. 그러나 따옴표 따옴표를 두 개 이상 사용해야하는 경우에는 "cmd/k 'python \'path 1 \ '\'와 같이 불쾌한 이스케이프 처리를해야합니다. 경로 2 \ '' ".

    이 문제에 대한 좋은 해결책이 하나의 문자열로보다는 목록으로 매개 변수를 전달합니다. 하위 프로세스는이 작업을 수행 할 수 있습니다.

  7. 쉽게에서 데이터를 반환 할 수 없습니다 하위 프로세스.

    물론 stdout을 사용할 수 있습니다.하지만 디버깅을 위해 인쇄물을 던지려면 어떻게해야합니까? 출력이 특정 방식으로 출력 될 것으로 예상되는 경우 부모를 망칠 것입니다. 함수에서 한 문자열 또 다른 이브를 돌려 보내라. rything 잘 작동합니다.

  8. 모호한 명령 줄 플래그 및 엉뚱한 터미널 기반 도움말 시스템.

    os 레벨 앱을 사용할 때 자주 사용하는 문제입니다. 내가 언급 한/k 플래그와 마찬가지로, cmd 윈도우를 열어 놓은 것처럼, 누가 그 아이디어 였는가? 유닉스 애플 리케이션은이 점에서 훨씬 친숙하지 않는 경향이있다. 다행히도 Google이나 StackOverflow를 사용하여 필요한 답변을 찾을 수 있습니다. 그러나 그렇지 않다면 많은 지루한 독서와 좌절스러운 시행 착오가 있습니다.

  9. 외부 요인.

    이런 종류의 퍼지입니다. 그러나 자신이 만든 스크립트의 상대적으로 보호 된 항구를 외부 프로세스에 맡기려면 "외부 세계"를 훨씬 더 많이 다루어야합니다. 그리고 그것은 무서운 곳입니다.모든 종류의 일이 잘못 될 수 있습니다. 그냥 무작위로 예를 들면 : 프로세스가 실행되는 cwd는 동작을 수정할 수 있습니다.

다른 문제가있을 수 있지만 지금까지 적어 두었습니다. 추가하려는 다른 장애물이 있습니까? 이러한 문제를 해결하기위한 제안은 무엇입니까?

답변

2

하위 프로세스 모듈을 확인하십시오. 출력 분리에 도움이됩니다. 하나의 스트림에서 별도의 출력 스트림이나 일종의 출력 태깅을 둘러 볼 방법이 없습니다.

교수형 처리 문제도 어렵습니다. 내가 할 수 있었던 유일한 해결책은 타이머를 외부 프로세스에 넣고 할당 된 시간에 복귀하지 않으면 죽이는 것입니다. 조잡하고, 고약한, 그리고 다른 사람이 좋은 해결책을 가지고 있다면, 나는 그것을 듣기를 너무 좋아해서 그것을 사용할 수 있습니다.

완전히 관리되지 않는 종료 문제를 해결하기 위해 할 수있는 한 가지 방법은 pid 파일의 디렉토리를 유지하는 것입니다. 외부 프로세스를 시작할 때마다 프로세스의 pid 인 이름으로 pid 파일 디렉토리에 파일을 작성하십시오. 프로세스가 정상적으로 종료되었다는 것을 알면 pid 파일을 지우십시오. pid 디렉토리의 내용을 사용하여 충돌시 다시 정리하거나 다시 시작할 수 있습니다.

이것은 만족 스럽거나 유용한 답변을 제공하지 않을 수도 있지만 시작일 수도 있습니다.

+0

좋은 아이디어입니다. 감사합니다. 나는 아무도 어떻게 반응하지 않았는지를 인정하는 것으로 표시 할 것입니다. 나는이 질문에 더 관심을 가지지 않았다는 것에 놀라움을 금치 못했다. 아 글쎄, 그저 단순한 해결책이 없다는 것을 보여줄 것입니다. –