Threading w aplikacji PyQt: używać wątków Qt czy wątków Pythona?

Piszę aplikację GUI, która regularnie pobiera dane za pośrednictwem połączenia internetowego. Ponieważ pobieranie trwa chwilę, powoduje to, że interfejs użytkownika nie reaguje podczas procesu pobierania (nie można go podzielić na mniejsze części). Dlatego chciałbym zlecić połączenie internetowe do osobnego wątku roboczego.

[Tak, wiem, teraz mam dwa problemy .]

W każdym razie, aplikacja używa PyQt4, więc chciałbym wiedzieć, jaki jest lepszy wybór: użyj wątków Qt lub użyć modułu Python threading? Jakie są zalety / wady każdego z nich? A może masz zupełnie inną propozycję?

Edit (re bounty): podczas gdy rozwiązaniem w moim konkretnym przypadku będzie prawdopodobnie użycie nieblokującego żądania sieciowego, takiego jak Jeff Ober i Lukáš Lalinský zasugerował (więc zasadniczo pozostawiając problemy z współbieżnością implementacji sieciowej), nadal chciałbym bardziej dogłębnej odpowiedzi na pytanie ogólne:

Jakie są zalety a wady używania wątków PyQt4 (tj. Qt) nad natywnymi wątkami Pythona (z modułu threading)?


Edit 2: Dzięki wszystkim za odpowiedzi. Chociaż nie ma 100% zgody, wydaje się, że istnieje powszechna zgoda co do tego, że odpowiedzią jest "użyj Qt", ponieważ zaletą tego jest integracja z resztą biblioteki, nie powodując przy tym żadnych prawdziwych wad.

Dla każdego, kto chce wybrać pomiędzy dwoma implementacjami wątków, Gorąco polecam przeczytanie wszystkie odpowiedzi podane tutaj, w tym wątek listy dyskusyjnej PyQt, do którego linkuje.

Było kilka odpowiedzi, które rozważałem do nagrody; w końcu wybrałem Abbota dla bardzo istotnego odniesienia zewnętrznego; było to jednak bliskie spotkanie.

Jeszcze raz dziękuję.
Author: Community, 2009-10-20

7 answers

To było dyskutowane nie tak dawno temu na liście dyskusyjnej PyQt. Cytując Komentarze w temacie:

To w większości to samo. Główną różnicą jest to, że QThreads są lepsze zintegrowany z Qt (asynchroniczne sygnały/sloty, pętla zdarzeń, itp.). Ponadto, nie możesz używać Qt z wątku Pythona (nie możesz na przykład Opublikuj Zdarzenie do głównego wątku za pomocą QApplication.postEvent): ty potrzebuję QThread, żeby to zadziałało.

Ogólna zasada kciukiem może być użycie QThreads, jeśli zamierzasz w jakiś sposób współdziałać z Qt, a w inny sposób używać wątków Pythona.

I kilka wcześniejszych komentarzy na ten temat od autora PyQt: "oba są opakowaniami wokół tych samych implementacji natywnych wątków". I obie implementacje używają GIL w ten sam sposób.

 89
Author: abbot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-03 15:33:38

Wątki Pythona będą prostsze i bezpieczniejsze, a ponieważ są przeznaczone dla aplikacji opartych na I / O, są w stanie ominąć GIL. Czy rozważałeś nieblokujące wejścia / wyjścia za pomocą skręconych lub nieblokujących gniazd / select?

EDIT: więcej o wątkach

WÄ…tki Pythona

Wątki Pythona są wątkami systemowymi. Jednak Python używa globalnej blokady interpretera (Gil), aby zapewnić, że interpreter wykonuje tylko określony rozmiar bloku bajtowego kodu instrukcje na raz. Na szczęście Python uwalnia GIL podczas operacji wejścia/wyjścia, czyniąc wątki użytecznymi do symulacji nieblokujących we/wy.

Ważne zastrzeżenie: Może to być mylące, ponieważ liczba instrukcji w kodzie bajtowym nie odpowiada liczbie linii w programie. Nawet pojedyncze przypisanie może nie być atomowe w Pythonie, więc blokada mutex jest konieczna dla dowolnego bloku kodu, który musi być wykonany atomicznie, nawet z GIL.

WÄ…tki QT

Gdy Python przekazuje kontrolę 3rd party skompilowany moduł, zwalnia GIL. Zadaniem modułu jest zapewnienie atomiczności tam, gdzie jest to wymagane. Gdy kontrola zostanie przekazana z powrotem, Python użyje GIL. Może to sprawić, że korzystanie z bibliotek innych firm w połączeniu z wątkami będzie mylące. Jeszcze trudniej jest użyć zewnętrznej biblioteki wątków, ponieważ dodaje niepewność co do tego, gdzie i kiedy kontrola jest w rękach modułu vs Tłumacz.

Wątki QT działają z wypuszczonym GIL. Wątki QT są w stanie wykonywać jednocześnie kod biblioteki QT (i inny skompilowany kod modułu, który nie nabywa GIL). Jednak Kod Pythona wykonywany w kontekście wątku QT nadal przejmuje GIL, a teraz musisz zarządzać dwoma zestawami logiki do blokowania kodu.

W końcu, zarówno wątki QT, jak i wątki Pythona są owijaczami wokół wątków systemowych. Wątki Pythona to marginalnie bezpieczniejsze w użyciu, ponieważ te części, które nie są napisane w Pythonie (w domyśle używając GIL) używają GIL w każdym przypadku (chociaż powyższe zastrzeżenie nadal ma zastosowanie.)

NieblokujÄ…ce we / wy

Wątki zwiększają złożoność Twojej aplikacji. Szczególnie, gdy mamy do czynienia z już złożoną interakcją między interpreterem Pythona a skompilowanym kodem modułu. Podczas gdy wielu uważa programowanie oparte na zdarzeniach za trudne do naśladowania, oparte na zdarzeniach, nieblokujące We/Wy często są znacznie mniej trudne do rozumowania niż wątki.

Przy asynchronicznych we/wy zawsze możesz być pewien, że dla każdego otwartego deskryptora ścieżka wykonania jest spójna i uporządkowana. Istnieją oczywiście problemy, które należy rozwiązać, takie jak co zrobić, gdy kod zależny od jednego otwartego kanału dalej zależy od wyników kodu, który ma być wywołany, gdy inny otwarty kanał zwraca dane.

Dobrym rozwiązaniem dla nieblokujących I/O opartych na zdarzeniach jest nowa biblioteka Diesel . Informatyka jest ograniczony do Linuksa w tej chwili, ale jest niezwykle szybki i dość elegancki.

Warto również poświęcić swój czas na nauczenie się pyevent , owijki wokół wspaniałej biblioteki libevent, która zapewnia podstawowy framework do programowania opartego na zdarzeniach przy użyciu najszybszej dostępnej metody dla Twojego systemu (określonej w czasie kompilacji).

 30
Author: Jeff Ober,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-29 11:52:07

Zaletą QThread jest to, że jest zintegrowany z resztą biblioteki Qt. Oznacza to, że metody obsługujące wątki w Qt będą musiały wiedzieć, w którym wątku działają, a aby przenosić obiekty między wątkami, należy użyć QThread. Inną przydatną funkcją jest uruchamianie własnej pętli zdarzeń w wątku.

Jeśli uzyskujesz dostęp do serwera HTTP, powinieneś rozważyć QNetworkAccessManager.

 21
Author: Lukáš Lalinský,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-20 16:11:23

Zadałem sobie to samo pytanie, kiedy pracowałem nad PyTalk .

Jeśli używasz Qt, musisz użyć QThread, aby móc korzystać z Qt framework i przede wszystkim system sygnałowo-szczelinowy.

Dzięki silnikowi sygnału / gniazda będziesz mógł rozmawiać z jednego wątku do drugiego i z każdą częścią twojego projektu.

Co więcej, nie ma zbyt dużego pytania o wydajność tego wyboru, ponieważ oba są wiązaniami C++.

Oto moje doświadczenia z PyQt i nić.

Zachęcam do korzystania QThread.

 13
Author: Natim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-27 01:17:08

Jeff ma kilka dobrych punktów. Tylko jeden główny wątek może dokonać aktualizacji GUI. Jeśli musisz zaktualizować GUI z poziomu wątku, sygnały Qt-4 queued connection ułatwiają wysyłanie danych między wątkami i będą automatycznie wywoływane, jeśli używasz QThread; nie jestem pewien, czy będą, jeśli używasz wątków Pythona, chociaż łatwo jest dodać parametr do connect().

 9
Author: Kaleb Pederson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-19 17:29:36

Ja też nie polecam, ale mogę spróbować opisać różnice między wątkami CPython i Qt.

Po pierwsze, wątki CPython nie działają jednocześnie, przynajmniej nie w Pythonie. Tak, tworzą one wątki systemowe dla każdego wątku Pythona, jednak tylko wątek aktualnie posiadający globalną blokadę interpretera może być uruchomiony(rozszerzenia C i Kod FFI mogą go ominąć, ale bajtowy kod Pythona nie jest wykonywany, podczas gdy wątek nie posiada GIL).

Z drugiej strony mamy Qt wątki, które są zasadniczo wspólną warstwą nad wątkami systemowymi, nie mają globalnej blokady interpretera, a zatem mogą działać jednocześnie. Nie jestem pewien, jak radzi sobie z tym PyQt, jednak jeśli twoje wątki Qt nie wywołują kodu Pythona, powinny być w stanie działać jednocześnie (Pasek różnych dodatkowych blokad, które mogą być zaimplementowane w różnych strukturach).

Aby uzyskać dodatkowe dostrojenie, możesz zmodyfikować ilość instrukcji kodu bajtowego, które są interpretowane przed zmianą własności GIL-lower wartości oznaczają więcej przełączania kontekstowego (i prawdopodobnie wyższą responsywność), ale niższą wydajność na pojedynczy wątek (przełączniki kontekstowe mają swój koszt - jeśli próbujesz przełączać co kilka instrukcji, nie pomaga to w szybkości.)

Mam nadzieję, że pomoże w twoich problemach:)

 5
Author: p_l,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-28 09:15:37

Nie mogę skomentować dokładnych różnic między wątkami Pythona i PyQt, ale robiłem to, co próbujesz zrobić za pomocą QThread, QNetworkAcessManager i upewnij się, że zadzwonisz QApplication.processEvents(), gdy wątek jest żywy. Jeśli problem, który próbujesz rozwiązać, to responsywność GUI, pomoże późniejsze.

 0
Author: brianz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-25 05:24:57