Skip to content

2.17. 내용정리: 17일차

흔한 찐따 edited this page Mar 25, 2022 · 1 revision

라이브러리 (Library)

  • 전 세계의 파이썬 사용자들이 만든 유용한 프로그램을 모아 놓은 것이 바로 파이썬 라이브러리이다.
  • 라이브러리는 사전적인 의미로 "도서관"이라는 뜻 그대로 원하는 정보를 찾아보는 곳이다.
  • 모든 라이브러리를 전부 다 알 필요는 없으며, 어떤 일을 할 때 어떤 라이브러리를 사용해야 한다는 정도만 알면 된다.
    • 필요한 라이브러리가 있다면, 라이브러리 문서를 참고해서 사용법을 익히면 된다.
    • 따라서 라이브러리를 직접 만드는 경우, 이를 문서화 해놓는 것이 중요하다.

모듈과 패키지, 라이브러리와의 관계

  • 모듈(Module) 은 함수와 변수, 클래스를 모아놓은 것을 의미한다.
  • 패키지(Package) 는 특정 기능과 관련된 여러 모듈을 하나의 디렉터리 안에 넣어 관리하는 것을 의미한다.
  • 라이브러리(Library) 는 여러 패키지와 모듈을 하나의 디렉터리 안에 모아놓은 것을 의미한다.

즉, 모듈을 M , 패키지를 P , 라이브러리를 L 로 정의하여 표현하자면 다음과 같은 관계가 성립한다.

  • MP 는 참이다.
  • 동시에 M1M2 ∪ ... = P 는 참이다.
  • PL 는 참이다.
  • 동시에 P1P2 ∪ ... = L 는 참이다.
  • MP 이므로, ML 가 성립한다.
  • 따라서, ( M , P ) ⊂ L 가 성립한다.
  • 동시에 ( M , P ) ∈ L 역시 성립한다.

파이썬 표준 라이브러리

  • 파이썬에서 기본적으로 제공하는 표준 라이브러리들이 존재한다.
  • 이 라이브러리들은 파이썬을 설치하면 같이 설치되는 라이브러리들이다.
  • 파이썬에서 기본적으로 제공하는 라이브러리가 어떤 것들이 존재하고 어떻게 사용하는지 알아두면 프로그래밍을 할 때 보다 작업이 수월해진다.
  • 아래의 라이브러리들은 파이썬에서 자주 사용되고 꼭 알아 두면 좋은 라이브러리를 중심으로 기술한 것이다.
  • 파이썬 공식 사이트의 라이브러리 래퍼런스 문서를 참고하면 다양한 라이브러리들을 확인할 수 있다.
    • 모든 라이브러리들을 전부 다 알 필요는 없고, 프로그래밍을 하다가 필요한 상황에서만 참고하면 된다.
    • 나처럼 파이썬에서 제공하는 라이브러리들 중 자주 사용되고 기본적인 개념들을 익히려면 wikidocs: 파이썬 라이브러리 문서를 참고하면 좋다.

sys

sys 모듈은 파이썬 인터프리터가 제공하는 변수와 함수를 직접 제어할 수 있게 해주는 모듈이다.

sys.argv

sys.argv 는 명령 행에서 인수를 전달한다.

C:/User/iamjjintta>python test.py Hello Python!
  • 명령 프롬프트 창에서 위의 예시처럼 test.py 뒤에 또 다른 값을 함께 넣어 주면 sys.argv 리스트에 그 값이 추가된다.
  • 아래의 예시에서 argv_test.py 파일은 C:/Users/iamjjintta/my_module 디렉터리에 저장했다고 가정한다.
# argv_test.py
import sys
print(sys.argv)

명령 프롬프트 창에서 cd 명령어를 통해 my_module 디렉터리로 들어간 뒤, python argv_test.py 인자값 과 같이 명령어를 입력하면 아래의 결과를 확인할 수 있다.

C:/Users/iamjjintta>cd my_module
C:/Users/iamjjintta/my_module>python argv_test.py Hello Python!
['argv_test.py', 'Hello', 'Python!']

python 명령어 뒤의 모든 것들이 공백을 기준으로 나뉘어서 sys.argv 리스트의 요소가 된다.

sys.exit

sys.exit 는 강제로 스크립트 종료한다.

sys.exit()
  • sys.exitCtrl + ZCtrl + D 단축키를 눌러서 대화형 인터프리터를 종료하는 것과 같은 기능을 한다.
  • 프로그램 파일 안에서 사용하면 프로그램을 중단시킨다.

sys.path

  • sys.path 는 파이썬 모듈들이 저장되어 있는 위치를 나타낸다.
  • 즉, 이 위치에 있는 파이썬 모듈은 경로에 상관없이 어디에서나 불러올 수 있다.
  • 따라서 sys.path 는 자신이 만든 모듈을 불러와 사용할 수 있다.

다음은 그 실행 결과이다.

import sys
print(sys.path)

결과

['', 'C:\\Windows\\SYSTEM32\\python310.zip', 'c:\\Python310\\DLLs', 
'c:\\Python310\\lib', 'c:\\Python310', 'c:\\Python310\\lib\\site-packages']

위 예에서 '' 는 현재 디렉터리를 의미한다.

# path_append.py
import sys
sys.path.append('C:/Users/iamjjintta/my_module')
  • 위와 같이 파이썬 프로그램 파일에서 sys.path.append 를 사용해 경로 이름을 추가할 수 있다.
  • 이렇게 하고 난 후에는 C:/Users/iamjjintta/my_module 디렉터리에 있는 파이썬 모듈을 불러와서 사용할 수 있다.
  • 참고로, 파일 경로를 표시할 때 명령 프롬프트 창에서는 / , \ 든 상관없지만, 소스 코드 안에서는 반드시 / 또는 \\ 기호를 사용해야 한다.

pickle

pickle 은 객체의 형태를 그대로 유지하면서 파일에 저장하고 불러올 수 있게 하는 모듈이다.

import pickle

data = {1: 'python', 2: 'you need'}
with open('test.txt', 'wb') as file:
    pickle.dump(data, file)
  • 위의 예시에서는 pickle 모듈의 dump 함수를 사용하여 딕셔너리 객체인 data 를 그대로 파일에 저장하는 방법을 보여 준다.
  • 다음은 pickle.dump 로 저장한 파일을 pickle.load 를 사용해서 원래 있던 딕셔너리 객체( data ) 상태 그대로 불러오는 예이다.
import pickle

with open('test.txt', 'rb') as file:
    data = pickle.load(file)

    # '{2:'you need', 1:'python'}'이 출력된다.
    print(data)

참고로, 위의 예시에서는 dict 를 사용했지만, pickle 모듈을 통해 어떤 자료형이든 저장하고 불러올 수 있다.

os

os 모듈은 환경 변수나 디렉터리, 파일 등의 OS 자원을 제어할 수 있게 해주는 모듈이다.

os.environ

  • os.environ 은 내 시스템의 환경 변수값을 가지는 객체이며, 환경 변수에 대한 정보를 dict 객체로 돌려준다.
  • 시스템은 제각기 다른 환경 변수 값을 가지고 있는데, os.environ 은 현재 시스템의 환경 변수값을 보여 준다.
import os

# 'environ({'PROGRAMFILES': 'C:\\Program Files', 'APPDATA': … })'과 같이 출력된다.
print(os.environ)
  • 반환된 객체가 dict 이기 때문에 다음과 같이 호출할 수 있다.
  • 다음은 내 컴퓨터 시스템의 PATH 환경 변수 내용이다.
import os

# 결과: 'C:\\Users\\iamjjintta\\AppData\\Local\\Programs\\Python\\Python310\\Scripts\\; ...'
print(os.environ['PATH'])

os.chdir

os.chdir 를 사용하면 다음과 같이 현재 디렉터리 위치를 변경할 수 있다.

import os
os.chdir('C:/Users/iamjjintta/my_module')

os.getcwd

os.getcwd 는 현재 자신의 디렉터리 위치를 돌려준다.

import os

# 결과: 'C:\\Users\\iamjjintta\\my_module'
print(os.getcwd())

os.system

  • 시스템 자체의 프로그램이나 기타 명령어를 파이썬에서 호출할 수도 있다.
  • 사용하는 방법은 os.system('명령어') 와 같이 사용한다.
  • 다음은 현재 디렉터리의 디렉터리 구조를 출력해주는 시스템 명령어 dir 을 실행하는 예이다.
import os
my_dir = os.system('dir')
print(my_dir)

os.popen

os.popen 은 시스템 명령어를 실행한 결과값을 읽기 모드 형태의 파일 객체로 돌려준다.

import os

with os.popen('dir') as file:
    print(file.read())

기타 유용한 os 관련 함수

  • 위에서 기술한 os 모듈의 함수 외에도 더 많은 함수들이 존재한다.
  • 아래는 os 모듈에서 제공하는 대표적인 함수들을 표로 나타낸 것이다.
함수 설명
os.mkdir('디렉터리') 새로운 디렉터리를 생성한다.
os.rmdir('디렉터리') 디렉터리를 삭제한다. (단, 디렉터리가 비어있어야 삭제가 가능하다.)
os.unlink('파일') 파일을 삭제한다.
os.rename(src, dst) src 라는 이름의 파일을 dst 라는 이름으로 바꾼다.

shutil

  • shutil 모듈은 파일을 복사해 주는 파이썬 모듈이다.
  • 아래의 예시는 src 라는 이름의 파일을 dst 로 복사하는 예시이다.
  • 만약 dst 가 디렉터리 이름이라면, src 라는 파일 이름으로 dst 디렉터리에 복사하고 동일한 파일 이름이 있을 경우에는 덮어쓴다.
import shutil
shutil.copy('src.txt', 'dst.txt')

위 예를 실행해 보면 src.txt 파일과 동일한 내용의 파일이 dst.txt 로 복사되는 것을 확인할 수 있다.

glob

  • 가끔 파일을 읽고 쓰는 기능이 있는 프로그램을 만들다 보면 특정 디렉터리에 있는 파일 이름 모두를 알아야 할 때가 있다.
  • 이럴 때 사용하는 모듈이 바로 glob 모듈이다.

glob.glob

  • glob.glob 은 디렉터리 안의 파일들을 읽어서 리스트 타입으로 반환한다.
  • * , ? 등의 특수 기호(이를 메타 문자라고 함)를 써서 원하는 파일만 읽어 들일 수도 있다.
  • 다음은 C:/Users/iamjjintta/my_module 디렉터리에 있는 파일 중 이름이 test 로 시작하는 파일을 모두 찾아서 읽어 들이는 예시이다.
import glob

# 결과: ['C:/Users/iamjjintta/my_module\\test.py', 'C:/Users/iamjjintta/my_module\\test.txt', 'C:/Users/iamjjintta/my_module\\test2.py', 'C:/Users/iamjjintta/my_module\\test3.py']
print(glob.glob('C:/Users/iamjjintta/my_module/test*'))

tempfile

tempfile 모듈은 파일을 임시로 만들어서 사용할 때 유용한 모듈이다.

tempfile.mkstemp

tempfile.mkstemp 는 중복되지 않는 임시 파일의 이름을 무작위로 만들어서 돌려준다.

import tempfile

filename = tempfile.mkstemp()

# 결과: 'C:\WINDOWS\TEMP\~-275151-0'
print(filename)

tempfile.TemporaryFile

  • tempfile.TemporaryFile 은 임시 저장 공간으로 사용할 파일 객체를 돌려준다.
  • 이 파일은 기본적으로 바이너리 쓰기 모드( wb )를 갖는다.
  • close 메서드가 호출되면 이 파일 객체는 자동으로 사라진다.
import tempfile
f = tempfile.TemporaryFile()
f.close()

time

time 은 시간과 관련된 모듈이다.

time.time

  • time.timeUTC(Universal Time Coordinated; 협정 세계 표준시) 를 사용하여 현재 시간을 실수 형태로 반환하는 함수이다.
  • 1970년 1월 1일 0시 0분 0초를 기준으로 지난 시간을 초 단위로 반환한다.
import time

t = time.time()
print(t)

time.localtime

time.localtimetime.time 이 반환한 실수 값을 사용해서 연도, 월, 일, 시, 분, 초, ... 의 형태로 바꾸어 주는 함수이다.

import time

t = time.time()
localtime = time.localtime(t)
print(localtime)

time.asctime

time.asctime 은 위의 time.localtime 에 의해서 반환된 튜플 형태의 값을 인수로 받아서 날짜와 시간을 알아보기 쉬운 형태로 반환하는 함수이다.

import time

t = time.time()
localtime = time.localtime(t)
asctime = time.asctime(localtime)
print(asctime)

time.ctime

  • time.asctimetime.ctime() 로 사용해 간편하게 표시할 수 있다.
  • asctime 과 다른 점은 ctime 은 항상 현재 시간만을 돌려준다는 점이다.
import time

ctime = time.ctime()
print(ctime)

time.strftime

  • time.strftime 함수는 시간에 관계된 것을 세밀하게 표현하는 여러 가지 포맷 코드를 제공한다.
  • 사용하는 방식은 time.strftime('출력할 형식 포맷 코드', time.localtime(time.time())) 와 같이 사용한다.

시간에 관계된 것을 표현하는 포맷 코드

아래는 시간에 관례된 것을 표현하는 포맷 코드를 표로 나타낸 것이다.

포맷 코드 설명
%a 요일 줄임말 Mon
%A 요일 Monday
%b 달 줄임말 Jan
%B January
%c 날짜와 시간을 출력함 06/01/01 17:22:21
%d 날(day) [01,31]
%H 시간(hour)-24시간 출력 형태 [00,23]
%I 시간(hour)-12시간 출력 형태 [01,12]
%j 1년 중 누적 날짜 [001,366]
%m [01,12]
%M [01,59]
%p AM or PM AM
%S [00,59]
%U 1년 중 누적 주-일요일을 시작으로 [00,53]
%w 숫자로 된 요일 [0(일요일),6]
%W 1년 중 누적 주-월요일을 시작으로 [00,53]
%x 현재 설정된 로케일에 기반한 날짜 출력 06/01/01
%X 현재 설정된 로케일에 기반한 시간 출력 17:22:21
%Y 년도 출력 2001
%Z 시간대 출력 대한민국 표준시
%% 문자 % %
%y 세기부분을 제외한 년도 출력 01

아래는 time.strftime 을 사용하는 예시이다.

import time

# 결과: '03/25/22'
print(time.strftime('%x', time.localtime(time.time())))

# 결과: 'Fri Mar 25 09:26:22 2022'
print(time.strftime('%c', time.localtime(time.time())))

time.sleep

  • time.sleep 은 초(seconds) 단위로 잠시 멈추는 함수이다.
  • time.sleep 함수는 주로 루프 안에서 많이 사용한다.
  • time.sleep 함수를 통해 일정한 시간 간격을 두고 루프를 실행할 수 있다.
import time

for i in range(10):
    print(i)
    time.sleep(1)
  • 위의 예시는 1초 간격으로 0 부터 9 까지의 숫자를 출력한다.
  • 위의 예시에서 볼 수 있듯, time.sleep 함수의 인수는 실수 형태를 쓸 수 있다.
  • 즉, 1 이면 1초, 0.5 면 0.5초가 되는 것이다.

calendar

calendar 모듈은 파이썬에서 달력을 볼 수 있게 해주는 모듈이다.

calendar.calendar

calendar.calendar(연도) 로 사용하면 그해의 전체 달력을 볼 수 있다.

import calendar
print(calendar.calendar(2022))

결과

                                  2022

      January                   February                   March
Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
                1  2          1  2  3  4  5  6          1  2  3  4  5  6
 3  4  5  6  7  8  9       7  8  9 10 11 12 13       7  8  9 10 11 12 13
10 11 12 13 14 15 16      14 15 16 17 18 19 20      14 15 16 17 18 19 20
17 18 19 20 21 22 23      21 22 23 24 25 26 27      21 22 23 24 25 26 27
24 25 26 27 28 29 30      28                        28 29 30 31
31

       April                      May                       June
Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
             1  2  3                         1             1  2  3  4  5
 4  5  6  7  8  9 10       2  3  4  5  6  7  8       6  7  8  9 10 11 12
11 12 13 14 15 16 17       9 10 11 12 13 14 15      13 14 15 16 17 18 19
18 19 20 21 22 23 24      16 17 18 19 20 21 22      20 21 22 23 24 25 26
25 26 27 28 29 30         23 24 25 26 27 28 29      27 28 29 30
                          30 31

        July                     August                  September
Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
             1  2  3       1  2  3  4  5  6  7                1  2  3  4
 4  5  6  7  8  9 10       8  9 10 11 12 13 14       5  6  7  8  9 10 11
11 12 13 14 15 16 17      15 16 17 18 19 20 21      12 13 14 15 16 17 18
18 19 20 21 22 23 24      22 23 24 25 26 27 28      19 20 21 22 23 24 25
25 26 27 28 29 30 31      29 30 31                  26 27 28 29 30

      October                   November                  December
Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
                1  2          1  2  3  4  5  6                1  2  3  4
 3  4  5  6  7  8  9       7  8  9 10 11 12 13       5  6  7  8  9 10 11
10 11 12 13 14 15 16      14 15 16 17 18 19 20      12 13 14 15 16 17 18
17 18 19 20 21 22 23      21 22 23 24 25 26 27      19 20 21 22 23 24 25
24 25 26 27 28 29 30      28 29 30                  26 27 28 29 30 31
31

calendar.prcal

calendar.prcal(연도) 를 사용해도 위와 똑같은 결과값을 얻을 수 있다.

import calendar
print(calendar.prcal(2022))

calendar.prmonth

  • calendar.prmonth 는 해당 년도의 월에 해당하는 달력을 반환한다.
  • 아래의 예시는 2022년 12월의 달력을 출력하는 예시이다.
import calendar
print(calendar.prmonth(2022, 12))

결과

   December 2022
Mo Tu We Th Fr Sa Su
          1  2  3  4
 5  6  7  8  9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

calendar.weekday

  • calendar.weekday 는 그 날짜에 해당하는 요일 정보를 돌려준다.
  • 월요일은 0 , 화요일은 1 , 수요일은 2 , 목요일은 3 , 금요일은 4 , 토요일은 5 , 일요일은 6 이라는 값을 돌려준다.
import calendar

# '5'가 출력된다.
print(calendar.weekday(2022, 12, 31))

위의 예시에서 5 가 출력되었으므로, 2022년 12월 31일은 5 에 해당하는 토요일임을 보여 준다.

calendar.monthrange

calendar.monthrange 함수는 입력받은 달의 1일이 무슨 요일인지와 그 달이 며칠까지 있는지를 튜플 형태로 돌려준다.

import calendar

# 결과값: (3, 31)
print(calendar.monthrange(2015,12))

위의 예시에서 (3, 31) 이 출력되었으므로, 2022년 12월 1일은 목요일이고, 이 달은 31일까지 있다는 것을 보여 준다.

random

random 모듈은 난수(규칙이 없는 임의의 수)를 발생시키는 모듈이다.

random.random

random.random01 사이의 실수 중에서 난수값을 반환한다.

import random

# 결과값: 0.18471036143699138
print(random.random())

random.randint

  • random.randint 은 첫 번째 값과 마지막 값 사이의 정수를 반환한다.
  • 아래의 예시에서는 1 에서 10 사이의 정수 중에서 난수값을 발생시키는 예시이다.
import random

# 결과값: 3
print(random.randint(1, 10))
  • 아래는 random.randint 을 활용한 함수 random_pop 를 정의한 것이다.
  • 아래에서 정의한 함수 random_pop 은 리스트의 요소 중에서 무작위로 하나를 선택하여 꺼낸 다음 그 값을 돌려준다.
  • 그 다음, 꺼낸 요소는 pop 메서드에 의해 사라진다.
import random

def random_pop(data):
    number = random.randint(0, len(data) - 1)
    return data.pop(number)

if __name__ == '__main__':
    data = [1, 2, 3, 4, 5]
    while data: 
        print(random_pop(data))

결과

2
3
1
5
4

random.choice

  • random.choice 는 입력으로 받은 리스트에서 무작위로 하나를 선택하여 반환한다.
  • 위의 예시에서 정의한 함수 random_poprandom 모듈의 choice 함수를 사용하여 다음과 같이 좀 더 직관적으로 만들 수도 있다.
def random_pop(data):
    number = random.choice(data)
    data.remove(number)
    return number

random.shuffule

random.shuffle 는 이터레이터 객체의 항목을 무작위로 섞어서 반환해준다.

import random

data = [1, 2, 3, 4, 5]
random.shuffle(data)

# 결과: [5, 1, 3, 4, 2]
print(data)

위의 예시에서 리스트 [1, 2, 3, 4, 5]shuffle 함수에 의해 무작위로 섞여서 [5, 1, 3, 4, 2] 로 변한 것을 확인할 수 있다.

webbrowser

  • webbrowser 모듈은 자신의 시스템에서 사용하는 기본 웹 브라우저를 자동으로 실행하는 모듈이다.

webbrowser.open

  • webbrowser.open 은 웹 브라우저가 이미 실행된 상태라면 입력 주소로 이동한다.
  • 만약 웹 브라우저가 실행되지 않은 상태라면 새로 웹 브라우저를 실행한 후 해당 주소로 이동한다.
  • 아래는 웹 브라우저를 자동으로 실행하고 해당 URL인 google.com 페이지로 이동하는 예시이다.
import webbrowser
webbrowser.open('http://google.com')

webbrowser.open_new

webbrowser.open_new 은 이미 웹 브라우저가 실행된 상태이더라도 새로운 창으로 해당 주소가 열리게 한다.

import webbrowser
webbrowser.open_new('http://google.com')

threading

threading 모듈은 한 프로세스에서 2가지 또는 그 이상의 일을 동시에 수행할 수 있게 하는 모듈이다.

쓰레드와 프로세스

  • 컴퓨터에서 동작하고 있는 프로그램을 프로세스(Process) 라고 한다.
  • 보통 1개의 프로세스는 한 가지 일만 하지만, 쓰레드(Thread) 를 사용하면 한 프로세스 안에서 2가지 또는 그 이상의 일을 동시에 수행할 수 있다.
  • 즉, 병렬 처리를 위한 기법이라고 할 수 있다.

threading.Thread

  • threading.Thread 은 쓰레드 객체를 사용하기 위한 Thread 클래스이다.
  • 인자값으로 targetargs 를 지정해서 사용해야 한다.
    • 매개 변수 target 은 실행할 함수를 의미한다.
    • 매개 변수 argstarget 에 필요한 인자값이며, tuple 타입으로 넘겨야 한다.
    • ex. threading.Thread(target=함수명, args=(인자값1, 인자값2, ...))

아래의 예시는 time.sleep 을 통해 5초간 대기하는 함수 long_task 를 정의한 예시이다.

import time

# 5초의 시간이 걸리는 함수
def long_task():
    for i in range(5):
        # 1초간 대기한다.
        time.sleep(1)
        print(f'working: {i}s')


print('Start')

# 함수 'long_task'를 5회 호출한다.
for i in range(5):
    long_task()

print('End')
  • 위에서 정의한 함수 long_task 은 수행하는 데 5초의 시간이 걸리는 함수이다.
  • 위 프로그램은 이 함수를 총 5번 반복해서 수행하는 프로그램이다.
  • 이 프로그램은 5초가 5번 반복되니 총 25초의 시간이 걸린다.
  • 하지만 앞에서 설명했듯이 스레드를 사용하면 5초의 시간이 걸리는 함수 long_task 를 동시에 실행할 수 있으니 시간을 줄일 수 있다.

Thread.start

  • 쓰레드 객체를 생성한 후에는 쓰레드_객체.start 메서드를 호출하여 쓰레드를 실행한다.
  • start 메서드는 쓰레드 객체의 run 메서드를 호출해주는 메서드이다.
  • 그리고 run 메서드는 target 을 호출하는 메서드이다.
  • 즉, 실행 순서는 start -> run -> target에 정의한 함수 순으로 호출된다.

아래는 위의 예시를 쓰레드로 활용한 예시이다.

import time
import threading

# 5초의 시간이 걸리는 함수
def long_task():
    for i in range(5):
        # 1초간 대기한다.
        time.sleep(1)
        print(f'working: {i}s')


print('Start')

threads = []
for i in range(5):
    # 쓰레드 객체를 생성한다.
    t = threading.Thread(target=long_task)
    threads.append(t)

for t in threads:
    # 'start' 메서드로 쓰레드를 실행한다.
    t.start()

print('End')
  • 이와 같이 프로그램을 수정하고 실행해 보면 25초 걸리던 작업이 5초 정도에 수행되는 것을 확인할 수 있다.
  • threading.Thread 을 사용하여 만든 쓰레드 객체가 동시 작업을 가능하게 해주기 때문이다.
  • 하지만 위 프로그램을 실행해 보면 StartEnd 가 먼저 출력되고, 그 이후에 쓰레드의 결과가 출력되는 것을 확인할 수 있다.
  • 그리고 프로그램이 정상 종료되지 않는다.
  • 프로그램으로부터 기대하는 것은 Start 가 출력되고 그다음에 쓰레드의 결과가 출력된 후 마지막으로 End 가 출력되는 것이다.

이 문제를 해결하기 위해서는 다음과 같이 프로그램을 수정해야 한다.

Thread.join

쓰레드 객체의 join 메서는 해당 쓰레드가 완전히 종료될 때까지 기다리게 한다.

import time
import threading

# 5초의 시간이 걸리는 함수
def long_task():
    for i in range(5):
        # 1초간 대기한다.
        time.sleep(1)
        print(f'working: {i}s')


print('Start')

threads = []
for i in range(5):
    t = threading.Thread(target=long_task)
    threads.append(t)

for t in threads:
    t.start()

for t in threads:
    # 'join' 메서드로 쓰레드가 종료될때까지 기다린다.
    t.join()

print('End')

위와 같이 join 메서드를 사용하면 원하던 결과를 볼 수 있게 된다.

흔한 찐따

안녕하세요, 흔한 찐따 입니다.

Clone this wiki locally