[python] PyQt 애플리케이션에서 스레딩 : Qt 스레드 또는 Python 스레드를 사용합니까?

웹 연결을 통해 정기적으로 데이터를 검색하는 GUI 응용 프로그램을 작성하고 있습니다. 이 검색에는 시간이 걸리므로 검색 프로세스 중에 UI가 응답하지 않게됩니다 (작은 부분으로 분할 할 수 없음). 이것이 제가 웹 연결을 별도의 작업자 스레드에 아웃소싱하려는 이유입니다.

[예, 알아요, 이제 두 가지 문제가 있습니다.]

어쨌든 응용 프로그램은 PyQt4를 사용하므로 Qt의 스레드를 사용하거나 Python threading모듈을 사용하는 것이 더 나은 선택인지 알고 싶습니다 . 각각의 장단점은 무엇입니까? 아니면 완전히 다른 제안이 있습니까?

편집 (바운티) : 제 특별한 경우의 솔루션은 아마도 Jeff OberLukáš Lalinský 와 같은 비 차단 네트워크 요청을 사용하는 것이지만 (따라서 기본적으로 동시성 문제는 네트워킹 구현에 남겨 둡니다), 저는 여전히 더 많은 것을 원합니다. 일반적인 질문에 대한 심도있는 답변 :

( threading모듈에서) 네이티브 Python 스레드보다 PyQt4 (즉 Qt) 스레드를 사용하는 장점과 단점은 무엇입니까 ?


편집 2 : 답변 해 주셔서 감사합니다. 100 % 동의는 없지만, 그 장점은 라이브러리의 나머지 부분과의 통합이면서도 실질적인 불이익을 유발하지 않기 때문에 대답이 “Qt 사용”이라는 광범위한 합의가있는 것 같습니다.

두 개의 스레딩 구현 중 하나를 선택하려는 사람에게는 abbot이 연결 하는 PyQt 메일 링 목록 스레드를 포함하여 여기에 제공된 모든 답변을 읽어 보는 것이 좋습니다 .

현상금에 대해 몇 가지 답변을 고려했습니다. 결국 나는 매우 관련성이 높은 외부 참조를 위해 abbot을 선택했습니다. 그러나 그것은 긴밀한 요청이었습니다.

다시 한 번 감사드립니다.



답변

이것은 얼마 전에 PyQt 메일 링리스트에서 논의 되었습니다 . 주제에 대한 Giovanni Bajo의 의견 을 인용 합니다.

거의 동일합니다. 주요 차이점은 QThreads가 Qt (비동기 신호 / 슬롯, 이벤트 루프 등)와 더 잘 통합된다는 것입니다. 또한 Python 스레드에서 Qt를 사용할 수 없습니다 (예를 들어 QApplication.postEvent를 통해 메인 스레드에 이벤트를 게시 할 수 없음). 작동하려면 QThread가 필요합니다.

경험상 일반적인 규칙은 Qt와 어떤 식 으로든 상호 작용하려는 경우 QThreads를 사용하고 그렇지 않으면 Python 스레드를 사용하는 것입니다.

그리고 PyQt의 저자는이 주제에 대해 이전에 언급했습니다 : “둘 다 동일한 네이티브 스레드 구현을 둘러싼 래퍼입니다”. 그리고 두 구현 모두 동일한 방식으로 GIL을 사용합니다.


답변

Python의 스레드는 더 간단하고 안전하며 I / O 기반 애플리케이션을위한 것이므로 GIL을 우회 할 수 있습니다. 즉, Twisted 또는 non-blocking 소켓 / select를 사용하는 non-blocking I / O를 고려 했습니까?

편집 : 스레드에 대한 추가 정보

파이썬 스레드

Python의 스레드는 시스템 스레드입니다. 그러나 Python은 글로벌 인터프리터 잠금 (GIL)을 사용하여 인터프리터가 한 번에 특정 크기의 바이트 코드 명령 블록 만 실행하도록합니다. 다행히도 Python은 입력 / 출력 작업 중에 GIL을 릴리스하므로 스레드가 비 블로킹 I / O를 시뮬레이션하는 데 유용합니다.

중요한주의 사항 : 바이트 코드 명령어 의 수가 프로그램의 행 수와 일치 하지 않기 때문에 이것은 오해의 소지가 있습니다 . 뮤텍스 잠금이 필요합니다, 그래서 심지어 하나의 과제는, 파이썬에서 원자하지 않을 수 있는 , 심지어 GIL로, 원자 적으로 실행해야하는 코드의 블록.

QT 스레드

Python이 타사 컴파일 모듈에 제어권을 넘겨 주면 GIL이 해제됩니다. 필요한 경우 원 자성을 보장하는 것은 모듈의 책임이됩니다. 제어가 다시 전달되면 Python은 GIL을 사용합니다. 이로 인해 스레드와 함께 타사 라이브러리를 사용하면 혼란 스러울 수 있습니다. 외부 스레딩 라이브러리를 사용하는 것은 모듈 대 인터프리터의 손에 제어가 언제 어디서 있는지에 대한 불확실성을 추가하기 때문에 훨씬 더 어렵습니다.

QT 스레드는 GIL이 릴리스 된 상태에서 작동합니다. QT 스레드는 QT 라이브러리 코드 (및 GIL을 획득하지 않는 기타 컴파일 된 모듈 코드)를 동시에 실행할 수 있습니다. 그러나 QT 스레드의 컨텍스트 내에서 실행되는 Python 코드 는 여전히 GIL을 획득하므로 이제 코드를 잠그기 위해 세트의 논리 를 관리 해야합니다.

결국 QT 스레드와 Python 스레드는 모두 시스템 스레드를 둘러싼 래퍼입니다. Python 스레드는 사용하기에 약간 더 안전합니다. Python으로 작성되지 않은 부분 (암시 적으로 GIL 사용)은 어떤 경우에도 GIL을 사용하기 때문입니다 (위의주의 사항은 여전히 ​​적용됨).

비 차단 I / O

스레드는 응용 프로그램을 매우 복잡하게 만듭니다. 특히 파이썬 인터프리터와 컴파일 된 모듈 코드 사이의 이미 복잡한 상호 작용을 다룰 때. 많은 사람들이 이벤트 기반 프로그래밍을 따르기 어렵다고 생각하지만, 이벤트 기반 비 차단 I / O는 스레드보다 추론하기가 훨씬 덜 어렵습니다.

비동기 I / O를 사용하면 열려있는 각 설명자에 대해 실행 경로가 일관되고 질서 정연하다는 것을 항상 확인할 수 있습니다. 하나의 개방형 채널에 의존하는 코드가 다른 개방형 채널이 데이터를 반환 할 때 호출되는 코드의 결과에 따라 달라지는 경우와 같이 해결해야 할 문제가 있습니다.

이벤트 기반 비 차단 I / O를위한 좋은 솔루션 중 하나는 새로운 Diesel 라이브러리입니다. 현재 Linux로 제한되어 있지만 매우 빠르고 매우 우아합니다.

시스템에 가장 빠른 방법을 사용하여 이벤트 기반 프로그래밍을위한 기본 프레임 워크를 제공하는 멋진 libevent 라이브러리를 둘러싼 래퍼 인 pyevent 를 배우는 것도 시간 가치가 있습니다 (컴파일 시간에 결정됨).


답변

의 장점은 QThread나머지 Qt 라이브러리와 통합된다는 것입니다. 즉, Qt의 스레드 인식 메서드는 실행되는 스레드를 알아야하며 스레드간에 개체를 이동하려면 QThread. 또 다른 유용한 기능은 스레드에서 자체 이벤트 루프를 실행하는 것입니다.

HTTP 서버에 액세스하는 경우 QNetworkAccessManager.


답변

PyTalk 작업을 할 때도 같은 질문을 했습니다 .

Qt QThread를 사용하는 경우 Qt 프레임 워크와 특히 신호 / 슬롯 시스템을 사용하려면을 사용해야합니다.

신호 / 슬롯 엔진을 사용하면 스레드에서 다른 스레드로 그리고 프로젝트의 모든 부분과 대화 할 수 있습니다.

또한 둘 다 C ++ 바인딩이기 때문에이 선택에 대한 성능 문제는 그리 많지 않습니다.

다음은 PyQt와 스레드에 대한 나의 경험입니다.

을 사용하는 것이 좋습니다 QThread.


답변

Jeff는 몇 가지 좋은 점을 가지고 있습니다. 하나의 주 스레드 만 GUI 업데이트를 수행 할 수 있습니다. 스레드 내에서 GUI를 업데이트해야하는 경우 Qt-4의 대기 연결 신호를 사용하면 스레드간에 데이터를 쉽게 전송할 수 있으며 QThread를 사용하는 경우 자동으로 호출됩니다. Python 스레드를 사용하는지 여부는 확실하지 않지만 .NET Framework에 매개 변수를 추가하는 것은 쉽습니다 connect().


답변

나도 정말 추천 할 수는 없지만 CPython과 Qt 스레드의 차이점을 설명해 볼 수 있습니다.

우선, CPython 스레드는 적어도 Python 코드가 아닌 동시에 실행되지 않습니다. 예, 각 Python 스레드에 대해 시스템 스레드를 생성하지만 현재 Global Interpreter Lock을 보유하고있는 스레드 만 실행할 수 있습니다 (C 확장 및 FFI 코드가이를 우회 할 수 있지만 스레드가 GIL을 보유하지 않는 동안 Python 바이트 코드는 실행되지 않음).

반면에 기본적으로 시스템 스레드에 대한 공통 계층 인 Qt 스레드는 Global Interpreter Lock이 없으므로 동시에 실행될 수 있습니다. PyQt가 어떻게 처리하는지 잘 모르겠지만 Qt 스레드가 Python 코드를 호출하지 않는 한 동시에 실행할 수 있어야합니다 (다양한 구조에서 구현 될 수있는 다양한 추가 잠금이 금지됨).

추가 미세 조정을 위해 GIL의 소유권을 전환하기 전에 해석되는 바이트 코드 명령의 양을 수정할 수 있습니다. 값이 낮을수록 컨텍스트 전환이 더 많고 응답 성이 높지만 개별 스레드 당 성능이 낮아집니다 (컨텍스트 전환에 비용이 있습니다. 속도에 도움이되지 않는 몇 가지 지침을 모두 전환 해보십시오.)

문제에 도움이되기를 바랍니다. 🙂


답변

파이썬과 PyQt는 스레드 사이의 정확한 차이에 대해 언급 할 수 없습니다,하지만 난 당신이 사용 할 시도하고 일을 봤는데 QThread, QNetworkAcessManager및 전화로 확인하는 QApplication.processEvents()스레드가 살아있다. GUI 응답 성이 실제로 해결하려는 문제라면 나중에 도움이 될 것입니다.