PyQt應用程式中的多執行緒:使用Qt還是Python執行緒?

華科雲商小雪發表於2024-02-20

多執行緒模組能夠更加高效得完成任務,但是在PyQt 應用程式中實現多執行緒可以使用 Qt 的執行緒模組(QThread)或者 Python 的 threading 模組。兩者各有優劣,具體選擇取決於專案需求和個人偏好。下面我們將以案例來說明兩種模組具體得優缺點。

1、問題背景

在 PyQt 應用程式中,編寫了一個定期透過 web 連線檢索資料的 GUI 應用程式。由於檢索過程需要一段時間,因此導致在檢索過程中 UI 無響應(無法將其拆分為更小的部分)。因此,需要將 web 連線外包給單獨的工作執行緒。

2、解決方案

  • Qt 執行緒:

    • 優勢:

      • 與 Qt 庫的其餘部分更好地整合。例如,Qt 中具有執行緒感知的方法需要知道它們在哪個執行緒中執行,並且要線上程之間移動物件,則需要使用 QThread。

      • 另一個有用的功能是線上程中執行自己的事件迴圈。

    • 劣勢:

      • 可能無法從 Python 執行緒訪問 Qt。例如,無法透過 QApplication.postEvent 將事件釋出到主執行緒。

  • Python 執行緒:

    • 優勢:

      • 更簡單、更安全。由於這是一個基於 I/O 的應用程式,因此它們能夠繞過 GIL。

      • Python 執行緒是系統執行緒。但是,Python 使用全域性直譯器鎖 (GIL) 來確保一次只執行一定大小的位元組碼指令塊。幸運的是,Python 在輸入/輸出操作期間會釋放 GIL,從而使執行緒對於模擬非阻塞 I/O 很有用。

    • 劣勢:

      • 由於 Python 的內建鎖 GIL(全域性直譯器鎖),Python 執行緒不能真正併發執行 Python 程式碼,包括了呼叫 Python API 和解釋 Python 位元組碼。

      • 多執行緒程式設計使應用程式複雜度大增,尤其是在處理 Python 直譯器和編譯模組程式碼之間的本來就複雜的互動時。

  • 非阻塞 I/O:

    • 透過非同步 I/O,可以始終確保每個開啟的檔案描述符的執行路徑一致且有序。

    • 例如:

      • QNetworkAccessManager:如果應用程式正在訪問 HTTP 伺服器,則應該考慮 QNetworkAccessManager。

      • Twisted 或非阻塞套接字/select:可以考慮使用 Twisted 或非阻塞套接字/select 實現非阻塞 I/O。

      • Diesel 庫:它目前僅限於 Linux,但它的速度非常快且非常優雅。

      • pyevent:它是 libevent 庫的包裝器,它提供了一個基本框架,用於使用系統最快的可用方法(在編譯時確定)進行基於事件的程式設計。

在 PyQt 應用程式中使用執行緒時,需要考慮以下幾點:

  • 如果需要從執行緒內更新 GUI,則應使用 Qt-4 的佇列連線訊號,以便輕鬆地跨執行緒傳送資料,並且如果使用 QThread,則會自動呼叫它們;不確定如果使用 Python 執行緒是否會呼叫它們,儘管很容易為 connect() 新增一個引數。

  • 只有一個主執行緒可以進行任何 GUI 更新。

  • Qt 執行緒與 Python 執行緒的主要區別在於,Qt 執行緒更好地整合到 Qt 庫的其餘部分。也就是說,Qt 中的執行緒感知方法需要知道它們在哪個執行緒中執行,並且要線上程之間移動物件,則需要使用 QThread。

  • Qt 執行緒在沒有 Global Interpreter Lock 的情況下執行,因此能夠併發執行。

  • Python 執行緒不需要 Global Interpreter Lock,因此能夠併發執行。

  • 如果 Qt 執行緒不呼叫 Python 程式碼,則它們應該能夠併發執行(除了可能在各種結構中實現的各種額外鎖之外)。

透過上述瞭解,我們應該清晰得知道,如果你的應用程式主要是 CPU 密集型任務,可能更傾向於使用 multiprocessing 模組。對於大多數 GUI 應用程式而言,使用 QThread 通常是更好的選擇,因為它更好地與 Qt 框架整合,並提供了方便的執行緒間通訊機制。所以說具體情況還得看專案要求,如果有不懂得可以評論區留言討論。


來自 “ ITPUB部落格 ” ,連結:https://blog.itpub.net/70034537/viewspace-3006832/,如需轉載,請註明出處,否則將追究法律責任。

相關文章