본문 바로가기
파이썬코드공유

Tkinter Background Task 백그라운드 작업

by 하이어시스템 2023. 8. 3.
반응형

하이어시스템 소개

 

하이어시스템 소개 feat.김프로

소개 안녕하세요, 저는 하이어시스템의 김프로입니다. 여러분들이 어려움을 겪고 계신 일상 업무를 저의 안정적이고 빠른 소프트웨어로 자동화하는 것, 그것이 저의 목표입니다. '하이어시스템

wise-office-worker.tistory.com

 

Tkinter로 개발한 GUI 화면이 중지되어 사용자 상호작용 불가

 

Tkinter 모듈을 사용하여 데스크톱 애플리케이션을 개발하는 과정에서 종종 발생하는 상황으로, 수행시간이 오래 소요되는 작업(예: 최소 2~3초 이상 소요되는 작업)을 호출하는 경우 해당 윈도우가 멈추는 현상입니다. 이렇게 되면 사용자는 더 이상 윈도우 애플리케이션과 상호작용할 수 없으며, 프로그레스 바의 값 증가등 GUI를 변경하는 코드마저도 중지 되므로 윈도우 화면을 변경할 수 없습니다. 이런 상황은 HTTP를 통해 파일을 다운로드하려고 할 때, 큰 파일을 쓰거나 읽을 때, SMTP를 통해 이메일을 보내려고 할 때, subprocess를 통해 명령을 실행하려고 할 때 등 여러 가지 상황에서 발생할 수 있습니다.

 

다음과 같은 예시 코드를 통해 화면의 상호작용이 멈추는 현상을 재연해 볼 수 있습니다.

import tkinter as tk
from tkinter import ttk
from urllib.request import urlopen

def write_list():
    with open('result.txt', 'w') as file:
        for i in range(1, 1000000000):
            file.write(str(i) + '\n')

root = tk.Tk()
info_label = ttk.Label(text="버튼을 클릭하면 파일을 생성합니다.")
info_label.pack()
download_button = ttk.Button(text="파일생성", command=write_list)
download_button.pack()
root.mainloop()

 

위 코드는 tkinter 표준 모듈을 사용하여 무거운 파일쓰기 작업을 수행하는 버튼이 있는 윈도우를 만듭니다. 버튼을 누르면 write_list() 함수가 실행됩니다. 이 함수 내에서 무거운 작업이 일어나는데 코드를 실행해보면 파일을 다운로드하는 동안 창이 멈추는 현상을 볼 수 있습니다.

화면이 중지되어 사용자와 상호작용 불가능한 현상

그런데 왜 이런 일이 발생할까요? 답은 간단합니다. tkinter, 특히 mainloop() 함수와 write_list() 함수가 동일한 스레드에서 실행되기 때문에 무거운 작업이 CPU를 점유하는 동안 Tk는 윈도우에서 발생하는 다른 여러 이벤트를 처리하거나 응답할 수 없습니다. 이로 인해 애플리케이션이 멈춘 것처럼 보이는 것입니다.

 

Python 표준 라이브러리에는 새 스레드를 생성할 수 있는 threading 모듈이 포함되어 있으므로 write_list() 함수를 독립적인 스레드로 이동하여 프로그램의 주 스레드를 차단하지 않게 설계할 수 있습니다.

import threading
import tkinter as tk
from tkinter import ttk
from urllib.request import urlopen

def write_list():
    with open('result.txt', 'w') as file:
        for i in range(1, 1000000000):
            file.write(str(i) + '\n')
            
def execute_write_list():
    t = threading.Thread(target=write_list)
    t.start()

root = tk.Tk()
info_label = ttk.Label(text="버튼을 클릭하면 파일을 생성합니다.")
info_label.pack()
download_button = ttk.Button(text="파일생성", command=execute_write_list)
download_button.pack()
root.mainloop()

 

write_list() 가 분리된 Thread로 실행되므로 사용자와 상호작용 가능
반응형