스레드

sz L·2023년 3월 14일
0

MINII_Project

목록 보기
8/15
post-thumbnail

동시성과 병렬성


  • 프로세스는 각각 독립된 메모리 영역(Code, Data, Stack, Heap)을 할당받습니다. 그리고 각 프로세스당 최소 1개의 메인 스레드를 갖습니다.
  • 스레드는 프로세스 내에서 Stack만 할당받고 나머지 영역은 공유합니다.

기본 스레드 하나, 서브 스레드 다섯개 동시에 진행

import threading
import time

class BackgroundWorker(threading.Thread): # 스레드를 상속받은 백그라운드 작업 클래스
    # 생성자
    def __init__(self, names: str) -> None:
        super().__init__()
        self.name = f'{threading.current_thread().name} : {names}'

    def run(self) -> None:
        print(f'BackgroundWorker start : {self._name}')
        # time.sleep(2)
        print(f'BackgroundWorker end : {self._name}')

if __name__ == '__main__':
    print('메인 스레드 시작') # 기본 프로세스 == 메인 스레드

    for i in range(5):
        name = f'서브 스레드 {i}'
        th = BackgroundWorker(name)
        th.start() # run 이 실행 됨

    print('메인 스레드 종료')        


노스레드 앱

Qt Designer


python 코드

# 스레드 미사용 앱
import sys
from PyQt5 import uic
from PyQt5.QtWidgets import *
from PyQt5.QtGui import * # QIcon 여기있음
from PyQt5.QtCore import * # Qt.white 여기 있음

class qtApp(QWidget):
    def __init__(self):
        super().__init__()
        uic.loadUi('./studyThread/threadApp.ui',self)
        self.setWindowTitle('노스레드 앱 v0.4')
        self.pgbTask.setValue(0)

        self.btnStart.clicked.connect(self.btnStartClicked)

    def btnStartClicked(self):
        self.pgbTask.setRange(0,100)
        for i in range(0,101): # 0~100까지 범위
            print(f'노스레드 출력 > {i}')
            self.pgbTask.setValue(i)
            self.txbLog.append(f'노스레드 출력 > {i}')

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = qtApp()
    ex.show()
    sys.exit(app.exec_())             

스레드 시작 누르면

스레드를 안 쓰면 프로세스가 충돌이 일어나기 때문에 스레드를 써야한다!


스레드 사용하는 앱

# 스레드 사용 앱
import sys
from PyQt5 import uic
from PyQt5.QtWidgets import *
from PyQt5.QtGui import * # QIcon 여기있음
from PyQt5.QtCore import * # Qt.white 여기 있음
import time

class BackgroundWorker(QThread): # pyqt5 스레드를 위한 클래스 존재
    procChanged = pyqtSignal(int)

    def __init__(self, count = 0, parent = None) -> None:
        super().__init__()
        self.main = parent
        self.working = False # 스레드 동작여부
        self.count = count 

    def run(self):
        # self.parent.pgbTask.setRange(0,100)
        # for i in range(0,101):
        #     print(f'스레드 출력 > {i}')
        #     self.parent.pgbTask.setValue(i)
        #     self.parent.txbLog.append(f'스레드 출력 > {i}')
        while self.working:
            self.procChanged.emit(self.count) # 시그널을 내보냄
            self.count += 1 # 값 증가만
            time.sleep(0.0001)

class qtApp(QWidget):
    def __init__(self):
        super().__init__()
        uic.loadUi('./studyThread/threadApp.ui',self)
        self.setWindowTitle('스레드 앱 v0.5')
        self.pgbTask.setValue(0)

        self.btnStart.clicked.connect(self.btnStartClicked)
        # 스레드 초기화
        self.worker = BackgroundWorker(parent=self,count=0)
        # 백그라운드 워커에 있는 시그널을 접근 슬롯함수
        self.worker.procChanged.connect(self.procUpdated)

        self.pgbTask.setRange(0,1000000)

    @pyqtSlot(int)
    def procUpdated(self, count):
        self.txbLog.append(f'스레드 출력 > {count}')
        self.pgbTask.setValue(count)
        print(f'스레드 출력 > {count}')

    def btnStartClicked(self):
        self.worker.start()
        self.worker.working = True


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = qtApp()
    ex.show()
    sys.exit(app.exec_())             

문제없이 잘 작동한다.
BUT 100%가 되어도 계속 진행됨


스레드 마무리

# 스레드 사용 앱
import sys
from PyQt5 import uic
from PyQt5.QtWidgets import *
from PyQt5.QtGui import * # QIcon 여기있음
from PyQt5.QtCore import * # Qt.white 여기 있음
import time

MAX = 10000

class BackgroundWorker(QThread): # pyqt5 스레드를 위한 클래스 존재
    procChanged = pyqtSignal(int) # 커스텀 시그널

    def __init__(self, count = 0, parent = None) -> None:
        super().__init__()
        self.main = parent
        self.working = False # 스레드 동작여부
        self.count = count 

    def run(self): # thread.start() --> run() 대신 실행
        while self.working:
            if self.count <= MAX:
                self.procChanged.emit(self.count) # 시그널을 내보냄(emit)
                self.count += 1 # 값 증가만
                time.sleep(0.0001) # 0.0000001 처럼 세밀하게 하면 GUI처리를 제대로 못 함
            else:
                self.working = False # 멈춤                

class qtApp(QWidget): # 전체동작
    def __init__(self):
        super().__init__()
        uic.loadUi('./studyThread/threadApp.ui',self)
        self.setWindowTitle('스레드 앱 v0.5')
        self.pgbTask.setValue(0)

        self.btnStart.clicked.connect(self.btnStartClicked)
        # 스레드 생성
        self.worker = BackgroundWorker(parent=self,count=0)
        # 백그라운드 워커에 있는 시그널을 접근 슬롯함수
        self.worker.procChanged.connect(self.procUpdated)
        self.pgbTask.setRange(0,MAX)

    # @pyqtSlot(int) : 데코레ㅔ이션
    def procUpdated(self, count):
        self.txbLog.append(f'스레드 출력 > {count}')
        self.pgbTask.setValue(count)
        print(f'스레드 출력 > {count}')

    def btnStartClicked(self):
        self.worker.start() # 스레드 클래스 run()실행
        self.worker.working = True
        self.worker.count = 0


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = qtApp()
    ex.show()
    sys.exit(app.exec_())             

profile
가랑비는 맞는다 하지만 폭풍은 내 것이야

0개의 댓글