PyQt6의 MultiThreading
이 글에서는 PyQt6에서 제공하는 클래스를 이용해 멀티쓰레딩을 이용하는 방법을 다룬다.
PyQt 정보
- 1. PyQt6을 이용하여 파이썬으로 GUI 어플리케이션 만들기
- 2. PyQt6 Signals, Slots & Events
- 3. Qt6 Widgets
- 4. PyQt6 Layouts
- 5. PyQt6 + Qt Designer
- 6. Qt의 Model View
- 7. PyQt6의 MultiThreading
Multithreading in Qt
Qt에서는 크게 두 종류의 쓰레드가 존재할 수 있다. 첫 번째는 메인 윈도우를 실행하고 위젯들의 동작을 관리하는 메인 쓰레드이다. Qt 어플리케이션에서는 이 메인 쓰레드가 항상 존재하게 된다.
그런데 메인 쓰레드 내에서 발생하는 모든 동작은 순차적으로 처리되므로, 실행 시간이 오래 걸리는 슬롯 함수 등을 호출하면 GUI는 해당 함수가 실행을 마칠 때까지 유저와 상호작용할 수 없게 된다.
이러한 류의 task를 워커 쓰레드에 맡기고 그 결과를 어플리케이션의 GUI 컴포넌트에 반영하는 방식으로 프리징 현상을 해결할 수 있다. 이는 GUI 컴포넌트가 실제 작업을 수행하는 쓰레드로부터 정보를 받는 소비자(consumer)의 역할을 하게 됨을 뜻한다.
워커 쓰레드 QThread
QThread
를 상속하여 만든 워커 쓰레드는 고유의 event loop를 가지며, PyQt의 시그널, 슬롯 메커니즘을 지원한다.
생성 방법
QThread
를 이용한 쓰레드 생성에는 두 가지 방식이 있다.
-
QObject
를 상속하는 워커 클래스 생성 후, 수행하고자 하는 작업 메소드를 구현한다. 워커 오브젝트 인스턴스를 만들고,QThread()
인스턴스도 만든다. 그 이후에 워커의.moveToThread()
메소드를 호출해 인자로 대상 쓰레드 인스턴스를 넣어 워커를QThread
화 한다. 이제 그 인스턴스에 대한 시그널과 슬롯을 connect한 후,.start()
메소드로 쓰레드를 시작한다. -
QThread
를 상속하는 워커 클래스를 생성 후, 수행하고자 하는 작업 메소드를run()
메소드에 구현한다. 워커 오브젝트 인스턴스를 만들고, 인스턴스에 대한 시그널과 슬롯을 connect한 후,.start()
메소드로 쓰레드를 시작한다.
첫 번째 방식은 고유의 이벤트 루프가 제공되나, 두 번째는 기본적으로 제공되지 않는다. .exec()
메소드를 호출함으로써 명시적으로 고유 이벤트 루프를 부여할 수 있다.
시그널
.started()
, .finished
: 각각 쓰레드가 시작, 종료 시 발생한다.
메소드
-
.start()
-
.wait()
-
.exit()
-
.quit()
: 이벤트 루프가 없는 쓰레드에선 아무 효과가 없으니 주의해야 한다. -
.isFinished()
-
.isRunning()
QRunnable
과 QThreadPool
QRunnable
은 멀티쓰레딩 대상이 되는 작업을 위한 컨테이너에 해당하고, QThreadPool
은 해당 작업을 쓰레딩할 수 있게 해주는 메소드에 해당한다.
class Worker(QRunnable):
'''
Worker thread
'''
@pyqtSlot()
def run(self):
'''
Your code goes in this function
'''
print("Thread start")
time.sleep(5)
print("Thread complete")
QRunnable
을 상속하여 원하는 작업을 수행할 Worker
클래스를 만든다.
이제 QThreadPool()
로 생성한 인스턴스에 Worker
의 인스턴스를 넘겨주면 된다.