2011-03-28 4 views
1

필자는 Twisted/PyQt 응용 프로그램을 가지고 있으며 다른 응용 프로그램들도 원격 자원에 연결되어 있습니다. 사용자가 창을 닫았을 때 가능한 경우 모든 연결을 셧다운하고 싶습니다. 그렇지 않으면 강제로 종료합니다.Twisted + qtreactor : 마지막 창을 닫은 후 정리하는 방법?

문제는 내가 연결부를 닫을 때까지는 반응기가 더 이상 나를 그렇게하도록 살아 있지 않다는 것입니다.

여기 내 응용 프로그램 코드가 없습니다 :

# Create app and connect the Twisted/Qt reactors 
app = QApplication(sys.argv) 
qtreactor.qt4reactor.install() 

# Shutdown Twisted when window is closed 
@defer.inlineCallbacks 
def stop(): 
    print "="*40, "Closing connections..." 
    yield closeConnections() 
    print "="*40, "closed." 

    print "="*40, "Stopping reactor..." 
    reactor.stop() 
    print "="*40, "stopped." 
app.connect(app, SIGNAL("lastWindowClosed()"), stop) 

reactor.runReturn() 
rc = app.exec_() 
exit(rc) 

그리고 여기 내 정리 코드의 버전을 박탈이다 : 첫 번째 인쇄 문에 도달

@defer.inlineCallbacks 
def closeConnections(): 
    for connection in connections: 
     print "Closing connection #%s" % connection 
     yield threads.deferToThread(popen("/foo/bar/cleanup %s" % connection)) 
     print "Connection closed." 

하고, 명령이 실행됩니다,하지만 결코 두 번째를 얻거나 for 루프를 여러 번 통과하지 마십시오.

내 분석이 맞습니까? 원자로가 이미 내려져있어 문제가 발생하지 않으므로 threads.deferToThread에서 다시는 듣지 못합니까? 아니면 다른 문제가 있습니까? 또한 어떻게 수정합니까?

덕분에, 조나단

답변

2

나는 정확히 그 lastWindowClosed() 신호 불을 모른다. 그러나, 원자로가 정지하기 전에 (당신이 원하는 일을하지 못하게하기 전에) 충분히 일찍 발생하더라도, PyQt는 당신의 stop 함수에 의해 반환 된 Deferred로 무엇을해야하는지 모른다. . 즉, 비동기 정리 코드가 실행되는 동안 종료 프로세스가 즐겁게 진행됩니다. GUI 종료는 네트워크 종료가 끝나기 전에 완료됩니다.

대신 reactor.addSystemEventTrigger('before', 'shutdown', stop)을 사용하십시오. 이것은 조금 늦게 또는 조금 늦게 lastWindowClosed()보다 조금 일찍 실행될 지 모르지만 반응기가 여전히 사용 가능할만큼 일찍 실행될 것이고 일 때은 지연된 함수 반환에주의해야합니다. . Deferred가 발동 할 때까지 종료가 실제로 중단됩니다. 이것은 당신이 당신의 청소를 할 필요가있는 모든 시간을 제공합니다. 모든 별도로

, 당신은 threads.deferToThread(popen("/foo/bar/cleanup %s" % connection))을하지 말아야 :

  • 당신은, deferToThread에 호출을 호출하지 않는 결과를 호출 가능한을 통과해야합니다. 작성된 것처럼 코드는 반응기 스레드에서 popen을 실행하고 호출 할 스레드에 파일 객체를 전달합니다 (물론 이해가되지 않습니다).
  • 스레드와 자식 프로세스를 함께 사용하는 것이 좋습니다. 당신은 그걸로 대부분 빠져 나올지 몰라요.
  • reactor.spawnProcess을 사용하면 스레드없이 스레드를 차단하지 않고 스레드와 프로세스를 혼합하지 않고도 하위 프로세스를 실행할 수 있습니다. spawnProcess의 모든 기능 (필요하지 않은 것으로 표시)이 필요하지 않은 경우 twisted.internet.utils.getProcessOutput을 참조하십시오.
+0

폴 : 죄송합니다. 내 popen (...)은 실제 코드가 아닙니다. 필자는 원격 클라이언트를 시작하기위한 쉘 명령과 TCP 클라이언트와 상호 작용하는 TCP 연결의 조합 인보다 복잡한 연결 메커니즘을 가지고 있습니다. 나는 세부 사항을 가지고 나의 예제를 복잡하게하지 않기를 선택했고, 이렇게함으로써 나의 closeConnection() 코드가 잘못되었다. 내 잘못이야. 감사합니다. 'reactor.addSystemEventTrigger ('before', 'shutdown', stop) '을 사용하도록 변경하면 매력처럼 작동합니다. 콜백을 할 때 원자로가 아직 살아 있고 예상대로 작동합니다. – Jonathan

+0

또한 버그를 발견했습니다. 위의 작업을 수행하면 원자로가 정지되지만 프로그램이 종료되지 않습니다. 'reactor.stop()'을 호출하면 qtreactor는'reactor.threadpool.stop()'을 호출하지 않고 ThreadPool 쓰레드는'threading.enumerate()'와 같이 실행 중임을 알 수 있습니다. 그런 다음 수동으로'reactor.threadpool.stop()'을 호출하면 프로그램이 종료됩니다. qtreactor의 stop()이이를 처리해야합니다. 이 문제에 대한 버그 보고서를 제출해야합니까? 그렇다면 어디에서? DeferToThread는 (내가하는 것처럼) 차단하고있는 레거시 라이브러리 코드와 상호 작용할 수있는 좋은 방법입니다. 따라서이 기능은 내가 할 수 있거나 할 수없는 기능이 아닙니다. – Jonathan

+0

PySide 기반 Qt 원자로가 한 가지 시도해보십시오. 우리는 PySide 라이센스가 호환 가능하기 때문에 (PyQt 라이센스가 아닌) Twisted에 다시 통합하려고합니다. 해당 원자로가 문제를 나타내면 http://twistedmatrix.com/trac/ticket/3977에 티켓을 남기거나 의견을 남기십시오. –

관련 문제