[Python] Pystray를 통한 멀티스레드 종류
개념을 먼저 설명하자면,
- 프로그램 : 어떤 작업을 하기 위해 실행할 수 있는 파일 (작업관리자에서 조회 불가)
- 프로세스 : 어떤 작업을 하기 위해 실행되고 있는 상태의 프로그램 (작업관리자에 조회 가능)
- 스레드 : 프로세스 내에서 동시에 진행되는 흐름의 단위로
스레드는 코드, 데이터, 힙, 스택으로 이루어져 있으며, 이 중에서 스택만 독립적인 영역으로 사용하고,
나머지 3가지 요소는 프로세스 내의 공유 자원으로써 다른 스레드와 같이 사용합니다.
이렇게 한 프로세스에서 여러 스레드가 생성되어 동시에 실행되는 구조를 멀티 스레드라고 지칭할 수 있습니다.
(크롬으로 유튜브를 보면서 웹서핑과 파일 다운로드를 동시에 진행하는 것이라고 볼 수 있음)
여기서는 Python에서 사용할 수 있는 Pystray 예제를 통하여 설명 진행하였습니다.
from pystray import Icon, Menu, MenuItem
from PIL import Image, ImageDraw
import threading
import time
# 아이콘 이미지 생성
def create_image():
img = Image.new('RGB', (64, 64), 'white')
draw = ImageDraw.Draw(img)
draw.rectangle((16, 16, 48, 48), fill='blue')
return img
# 일반 스레드 작업 함수
def background_task():
time.sleep(5)
print("[Thread] 완료")
# 종료 함수
def quit_app(icon, item):
print("[Main] 종료됨")
icon.stop()
# 트레이 아이콘 설정
icon = Icon("ThreadExample", create_image(), menu=Menu(
MenuItem("스레드 실행", run_thread),
MenuItem("Join 스레드 실행", run_join_thread),
MenuItem("Daemon 스레드 실행", run_daemon_thread),
MenuItem("종료", quit_app)
))
icon.run()
먼저 공통적으로 사용할, 트레이 아이콘 생성, 종료 함수, 실행 시 대기 함수 및 트레이 함수를 생성해 주고,
기본 스레드, Join 스레드, 데몬 스레드 함수명을 설정해 줍니다.
먼저 기본 스레드입니다.
def run_thread(icon, item):
t = threading.Thread(target=background_task)
print("[Thread] 기본 스레드 시작")
t.start()
print("[Main] 스레드 실행됨")
실행 결과는 기본 스레드가 실행되고 5초 후에 스레드가 완료되며, 스레드 실행 중 메인 스레드가 종료되어도
5초가 지난 후에 종료됨으로 메인 스레드와 독립적인 관계를 가집니다.
다음은 Join 스레드입니다.
def run_join_thread(icon, item):
t = threading.Thread(target=background_task)
print("[Thread] Join 스레드 시작")
t.start()
t.join()
print("[Main] 스레드 실행됨")
Join 스레드가 실행되고 5초 동안 Join 스레드는 다른 작업들을 일시 정지 시킵니다.
따라서 5초 동안 다른 메뉴 항목 클릭 등의 작업이 지연될 수 있습니다.
마지막으로 Daemon 스레드입니다.
def run_daemon_thread(icon, item):
t = threading.Thread(target=background_task)
print("[Thread] Daemon 스레드 시작")
t.daemon = True
t.start()
print("[Main] 스레드 실행됨")
Daemon 스레드가 실행되고 메인 스레드 종료 시 Daemon 스레드는 메인스레드와 함께 종료됩니다.
백그라운드 작업에 적합하지만, 작업 완료 보장을 요구하지 않는 경우에 사용합니다.
아래는 전체 코드입니다.
from pystray import Icon, Menu, MenuItem
from PIL import Image, ImageDraw
import threading
import time
# 아이콘 이미지 생성
def create_image():
img = Image.new('RGB', (64, 64), 'white')
draw = ImageDraw.Draw(img)
draw.rectangle((16, 16, 48, 48), fill='blue')
return img
# 일반 스레드 작업 함수
def background_task():
time.sleep(5)
print("[Thread] 완료")
# 기본 스레드 실행
def run_thread(icon, item):
t = threading.Thread(target=background_task)
print("[Thread] 기본 스레드 시작")
t.start()
print("[Main] 스레드 실행됨")
# join 스레드 실행
def run_join_thread(icon, item):
t = threading.Thread(target=background_task)
print("[Thread] Join 스레드 시작")
t.start()
t.join()
print("[Main] 스레드 실행됨")
# 데몬 스레드 실행
def run_daemon_thread(icon, item):
t = threading.Thread(target=background_task)
print("[Thread] Daemon 스레드 시작")
t.daemon = True
t.start()
print("[Main] 스레드 실행됨")
# 종료 함수
def quit_app(icon, item):
print("[Main] 종료됨")
icon.stop()
# 트레이 아이콘 설정
icon = Icon("ThreadExample", create_image(), menu=Menu(
MenuItem("스레드 실행", run_thread),
MenuItem("Join 스레드 실행", run_join_thread),
MenuItem("Daemon 스레드 실행", run_daemon_thread),
MenuItem("종료", quit_app)
))
icon.run()