본문 바로가기
  • ▒ 네모의 쉽게 배우는 네트워크 | 개발 ▒
파이썬 개발/Qypt5

Pyqt5 - gui 멈춤, gui freezing 해소, QThread 사용, multithreading, Long-running task offloading

by 너l모 2022. 9. 8.
반응형

※ 업무하면서 습득한 내용들을 정리해 놓은 포스팅입니다 :P 추가로 궁금하신 점은 댓글로 남겨주시고 필요한 자료 있으면 요청주세요! 잘못된 내용이 있으면 고쳐주시면 감사하겠습니다. 자료 퍼가실 때는 출처 남겨주세요!


 ο 목차

     


    ※ 코드 보는 방법 참고

    ㅇ 달러 기호($)가 있는 경우 -> 리눅스 터미널에서 CLI 명령어 입력

    ㅇ "=#" 기호가 있는 경우 -> psql 쉘에서 명령어 입력

    ㅇ 꺽쇠가 하나 있는 경우(>) -> 윈도우 명령 프롬프트(cmd)에서 명령어 입력

    ㅇ 꺽쇠가 세개 있는 경우(>>>) -> python 쉘에서 명령어 입력


    안녕하세요, 네모입니다. 

     

    pyqt5로 gui 코드 작성 중에 gui freezing 현상이 있어 문제 해결 방법을 공유하려고 합니다. 

     

    자세한 내용은 아래 사이트 참고 ↓↓↓↓

    ※ 참고 사이트 : https://realpython.com/python-pyqt-qthread/#freezing-a-gui-with-long-running-tasks

     

    Use PyQt's QThread to Prevent Freezing GUIs – Real Python

    In this step-by-step tutorial, you’ll learn how to prevent freezing GUIs by offloading long-running tasks to worker QThreads in PyQt.

    realpython.com

     

    1. 문제 사례

    gui 코드에서 Long-running task 실행시 gui 멈춤(gui freezing)* 현상 발생

     

    * GUI freezing 현상이란?

    - 위젯에서 장시간 처리가 필요한 함수(Long-runnint task)를 실행하는 경우 이벤트 루프가 그 함수를 처리하느라 위젯 상의 다른 인터랙션을 큐에만 차곡차곡 쌓아놓고 실제 처리를 못하게 되는 현상(gui freezing)

    - 함수가 돌아가는 5분 동안 gui는 멈춘 것처럼 보이다가 그 함수가 끝난 후에야 인터렉션들을 순차적으로 처리하기 때문에 멈춘 것처럼 보여도 인터랙션들이 큐에 차곡차곡 쌓이기 때문에 프리징 상태에서 종료 버튼을 누른다면 프리징이 끝난 후 프로그램이 종료됩니다. 

    2. 문제 원인

    메인 쓰레드의 자원을 Long-running task가 점유하여 task가 끝날 때까지 gui 이벤트 처리 불가

     

    3. 해결 방법 개요

    QThread를 사용하여 Long-running task를 메인 쓰레드와 분리된 별도의 쓰레드로 실행시킴(Long-running task offloading) 

     

    ※ QThread 활용시 주의 사항 ↓↓ 

    더보기

    (1) Long-running task를 실행시키기 위한 모든 코드는 Long-running task 코드 안에 있어야 함

       - 예시) lambda를 사용하는 경우 쓰레드 생성 불가 ↓↓ 아래 내용 참고

        https://stackoverflow.com/questions/50596027/pyqt5-qthread-not-working-gui-still-freezing

     

    PyQt5 QThread not working, gui still freezing

    I have this code (if you have pyqt5, you should be able to run it yourself): import sys import time from PyQt5.QtWidgets import QApplication, QPushButton, QVBoxLayout, QWidget from PyQt5.QtCore i...

    stackoverflow.com

    (2) 사용자 지정 signal을 사용하는 경우(ex. finished) 인스턴스 어트리뷰트가 아닌 클래스 어트리뷰트(class attributes)로 생성

    (3) GUI의 위젯은 thread-safe*가 아니기 때문에 thread 생성시 위젯과 관련된 요소들 배제

     * thread-safe : 멀티 스레드 프로그래밍에서 일반적으로 어떤 함수나 변수, 혹은 객체가 여러 스레드로부터 동시에 접근이 이루어져도 프로그램의 실행에 문제가 없음을 의미함

      - 예시) 아래는 제가 stackoverflow에 문의한 내용인데 혹시 참고하실 분들 있으면 참고하세요↓↓

        https://stackoverflow.com/questions/73630171/pyqt5-gui-still-freezing-even-though-using-qthread

     

    pyqt5) GUI still freezing even though using QThread

    What I intended when I click 'start' button on Subwindow then loading logo animation starts, and RSC function(Long running function) works separately. Real work when I click the "start"

    stackoverflow.com

     

    4. 문제 해결 방법

    1) Thread 별도 생성을 위한 Thread 클래스(worker) 생성

    from PyQt5 import QtCore
    
    # QThread를 상속하는 Thread 클래스 생성
    class Thread(QtCore.QThread):
    	# 쓰레드 종료시 종료 signal 생성을 위한 사용자 지정 시그널 객체 생성
        finished = QtCore.pyqtSignal()
        # Long-running task 함수 생성 부분
        def LongRunningTask(self):
            sleep(10)
        # Thread 시작시 수행할 동작 지정
        def run(self):
        	# Long-running task 실행
            self.LongRunningTask()
            # finished 시그널 발생
            self.finished.emit()

     

    2) Thread 수행 코드

    def ThreadStart(self) :
        # thread 생성
        self.thread = Thread()
        # thread의 finished 시그널 발생시 thread 종료
        self.thread.finished.connect(self.thread.quit)
        self.thread.finished.connect(self.thread.deleteLater)
        # thread의 run 메소드 수행
        self.thread.start()

     

    해당 함수 부분만 별도 thread로 수행 시키면 gui 프리징 현상 없이 정상적으로 잘 동작할 겁니당

    혹시 관련해서 궁금한 부분 있으시면 댓글 주세요~


    ※ 좋아요와 구독은 큰 힘이 됩니다. 감사합니다. 

     

     

    반응형

    댓글