17. 쓰레드 (Thread) > 파이썬 기초

본문 바로가기
사이트 내 전체검색

회원로그인

올서베이넷
무료 온라인 설문 사이트
OVITII
웹 프레젠테이션 도구

파이썬 기초

17. 쓰레드 (Thread)

페이지정보

글쓴이 관리자 조회 38,637 조회 날짜 19-06-04 14:46 / Update:19-11-14 15:41
댓글 0 댓글

SNS 공유

  • 트위터로 보내기
  • 페이스북으로 보내기
  • 구글플러스로 보내기

내용

쓰레드

 

 

프로그램이 하나의 일을 처리할 때, CPU는 메모리에 프로그램에 관련된 DATA를 저장하고 처리하게 된다.

 

이렇게 일련의 프로그램을 진행하는 것을 프로세스(Process)라고 한다.

 

하나의 프로그램을 실행시키면, 그 프로그램은 한개의 프로세스를 가지게 된다.

 

윈도우의 작업관리자를 보면 알 수 있다.

 

3109821127_1559676714.532.png

 

 

한개의 프로그램이 한개의 프로세스만을 가지는 것은 아니다. 프로그램의 성격이나 필요에 따라 프로그램에서 또 다른 프로세스를 생성할 수 있다.

 

새로운 프로세스를 생성하는 것을 프로세스 포크(Fork)라고 한다. 

 

프로세스는 프로그램이 작동하기에 필요한 많은 데이터를 가지고 있다. 만약 프로세스 포크를 하게되면, 새로 생성된 프로세스는 이전의 프로세스와 동일한 데이터를 가져가게 된다.

 

이것은 프로세스간의 데이터 공유를 위해 많은 뒤처리가 필요하고, 또한 컴퓨터 자원의 소모를 가져온다.

 

 

따라서, 굳이 새로운 프로세스는 필요하지 않지만, 하나의 일을 따로 처리해야할 때 사용하는 것이 쓰레드이다.

 

좀 극단적인 예를 들자면, 프로세스가 사람이라면 쓰레드는 팔이라고 생각하면 된다.

 

보통 두 개의 팔을 가지고 작업을 하는데, 손이 더 필요한 일이 생겼다고 하자. 이때 사람을 한명 더 불러와야 되지만 팔이 하나가 더 있다면 다른 사람을 굳이 불러올 필요가 없다.

 

사람 한명이 더 존재하면, 생각을 공유하기 위해 회의를 해야하고, 밥값이 더 나가고 등등... 처리해야할 일이 더 복잡해진다.

 

하지만 한명의 사람에게 팔만 하나 더 생긴다면, 기존의 하던 일에 아무런 추가 작업 없이 일만 더 처리할 수 있다.

 

아래는 쓰레드 구조를 나타내는 그림이다. 

 

3109821127_1559677484.1901.png

출처 - https://www.python-course.eu/threads.php

 

 

그림을 보면 알 수 있듯이, 쓰레드는 프로세스 안에서 자료를 공유하며 일을 처리하는 새로운 루틴이라는 것을 알 수 있다.

 

그렇다면 쓰레드를 사용해야하는 이유는 무엇인가?

 

여러가지 이유가 있다. 

 

우리가 일반적으로 생각하기에 컴퓨터는 여러 개의 일을 동시에 처리한다고 알고 있다.

맞는 말이기는 하지만 실질적으로 하나의 CPU는 하나의 일, 즉 하나의 프로세스만 처리할 수 있다. 하지만 워낙 빠르게 프로세스를 오가며 일을 처리하기에 우리가 보기에는 모든 일이 동시에 처리되는 것처럼 보이는 것이다.

이것을 시분할 시스템이라고 한다. 

 

보통 컴퓨터에서 가장 많은 시간이 필요한 것이 입출력이다.

우리가 알지 못하는 수많은 입출력 방법과 데이터가 있지만,  쉽게 생각하면 입력은 키보드입력, 마우스 입력 등등을 의미하고 출력은 모니터 출력, 프린터 출력등을 의미한다.

 

CPU의 연산처리능력은 인간이 상상할 수 없을 정도로 빠르다. 따라서 하드웨어에 관련된 입출력 처리는 CPU입장에서는 느려터진 작업이 된다. 

앞서 서술했듯이 CPU는 한번에 하나의 일만 처리 한다고 했다. 만약 CPU가 하나의 프로세스 안에서 누군가의 입력을 기다리고 있다면, 입력이 마무리가 될때까지는 다른 일을 할 수가 없다.

CPU 입장에서는 느려터진 입력을 위해서 아무것도 하지 못하고 무한정 기다리는 꼴이 된다. 

 

이때, 일을 효율적으로 하기 위해서 일을 분산시킬 수 있다. 입력을 기다리는 프로세스, 입력을 받아서 처리하는 프로세스, 처리 후 출력하는 프로세스...

하지만 프로세스가 늘어나면 데이터 공유를 위해서 처리해줘야 할 일이 많아지므로, 하나의 프로세스 안에 다른 쓰레드를 생성하여 작은 일들을 처리해주게 되면, 자원 소모없이 여러가지 일을 동시에 처리할 수 있게 된다. 

 

요약하면, 쓰레드는 한개의 프로세스 안에서 데이터를 공유하며 일을 동시에 처리하기 위한 작은 프로세스 정도로 이해하면 된다.

 

쓰레드를 만드는 방법은 간단하다.

 

실행할 함수를 만들고, 그 함수를 쓰레드로 실행하면 된다.

 

함수를 쓰레드로 만드는 방법

import threading

 

#실행할  함수

def threadingtest1(a, b):

    print(a, b)

 

#쓰레드로 실행

thread1 = threading.Thread(target=threadingtest1, args=(a, b))
thread1.daemon = True

thread1.start()

 

 

target= threadingtest1  

쓰레드로 실행할 대상을 정한다. 함수 뒤에 괄호 () 는 쓰지 않는다.

 

인수는 args=(a,b) 처럼 튜플로 전달하는데, 인수가 한개일 경우에는 아래 처럼 인수 뒤에 쉼표를 적어준다.

args = (a,) 

 

thread1.daemon 은 쓰레드를 데몬으로 처리할 것인가를 설정한다.

데몬 프로세스일 경우, 부모프로세스가 죽으면 쓰레드도 같이 죽는다. 만약 thread1.daemon = False로 처리했다면, 부모프로세스가 죽어도 쓰레드가 완료될때까지 끝까지 실행한다. default는 False이다.

 

threa1.start()

설정한 쓰레드를 실행한다.

 

 

클래스를 쓰레드로 만드는 방법

class BackThread(threading.Thread):    
    def __init__(self):
        threading.Thread.__init__(self)
        self.daemon = True  
       
    def run (self): 

        for i in range(50):
            print(threading.currentThread().getName, i)

 

BackThread().start()

 

class BackThread(threading.Thread): 

쓰레드를 상속받아서 클래스를 생성한다.

 

def __init__(self):
        threading.Thread.__init__(self)

클래스의 초기화

 

def run (self): 

쓰레드 클래스를 start했을때 실행되는 메서드

 

BackThread().start() 

쓰레드 클래스 실행

 

 

 

위에서 봤듯이 쓰레드로 함수와 클래스를 만드는 방법은 간단하다.

 

 

일반적으로 for 구문을 실행하면, for 구문이 모두 완료되어야 다른 구문이 실행된다.

 

하지만 쓰레드를 이용하면 각자의 쓰레드가 따로 작동하게 되므로, 각 쓰레드에 존재하는 for 구문이 서로 간섭없이 따로 움직이게 된다. 실제 코드를 통해서 어떻게 되는지 확인해보자.

 

 

전체 코드

import threading
import time

 

class BackThread(threading.Thread):

    def __init__(self):
        threading.Thread.__init__(self)
        #self.daemon = True  

   
    def run (self): 
        for i in range(50):
            print(threading.currentThread().getName, i)
            time.sleep(0.1)   
        
def threadingtest1():
    for i in range(50):
        print(threading.currentThread().getName, i)
        time.sleep(0.1)
    
def threadingtest2():  
    for i in range(50):
        print(threading.currentThread().getName, i) 
        time.sleep(0.1)       
    
    
thread1 = threading.Thread(target=threadingtest1, args=())
#thread1.daemon = True

thread2 = threading.Thread(target=threadingtest2, args=())
#thread2.daemon = True

 

thread1.start()
thread2.start()
BackThread().start()

'''

<bound method Thread.getName of <Thread(Thread-1, started 13532)>> 42
<bound method Thread.getName of <BackThread(Thread-3, started daemon 13560)>> 42
<bound method Thread.getName of <Thread(Thread-2, started 13464)>> 42
<bound method Thread.getName of <Thread(Thread-1, started 13532)>> 43
<bound method Thread.getName of <BackThread(Thread-3, started daemon 13560)>> 43
<bound method Thread.getName of <Thread(Thread-2, started 13464)>> 43
<bound method Thread.getName of <Thread(Thread-1, started 13532)>> 44
<bound method Thread.getName of <BackThread(Thread-3, started daemon 13560)>> 44
<bound method Thread.getName of <Thread(Thread-2, started 13464)>> 44
<bound method Thread.getName of <Thread(Thread-1, started 13532)>> 45
<bound method Thread.getName of <BackThread(Thread-3, started daemon 13560)>> 45
<bound method Thread.getName of <Thread(Thread-2, started 13464)>> 45
<bound method Thread.getName of <Thread(Thread-1, started 13532)>> 46
<bound method Thread.getName of <BackThread(Thread-3, started daemon 13560)>> 46
<bound method Thread.getName of <Thread(Thread-2, started 13464)>> 46
<bound method Thread.getName of <Thread(Thread-1, started 13532)>> 47
<bound method Thread.getName of <BackThread(Thread-3, started daemon 13560)>> 47
<bound method Thread.getName of <Thread(Thread-2, started 13464)>> 47

 

 

 

3109821127_1559680886.6656.png

 

 

하나의 프로그램안에서 여러가지 일을 동시 다발적으로 처리해야할 때, 새로운 프로세스를 생성하는 것보다 쓰레드를 이용하는 것이 효율적이다.

그리고 최근에는 웹을 통해 데이터를 받아오는 경우가 많이 있다. 

이럴 경우 네트워크를 통해 데이터를 받아오거나, 웹 페이지에 접속하거나 할때 서버나 네트워크 라인의 상황에 따라서 시간이 많이 걸리는 경우가 있다.

만약 하나의 프로세스 안에서 웹 페이지를 접속하는 코드를 만들었다면, 이와 같이 서버에 문제가 있는 경우 웹 페이지를 정상적으로 접근할때까지 프로그램은 먹통(?) 상태가 된다. 

따라서 이런 경우 쓰레드를 통해서 웹 페이지에 접속하고, 완료된 데이터는 다른 함수를 통해서 처리해주면 프로그램이 먹통이 되는 상태를 방지할 수 있다.

 

특정 프로그램 언어에서는 네트워크를 접속할때 쓰레드를 사용하지 않으면 에러로 간주하는 프로그램 언어도 있다.

댓글목록 sfs

총 30 건 , 1 페이지
게시물 검색
파이썬 기초 목록
번호 제목 글쓴이 조회 날짜
1 관리자 34605 05-02
2 관리자 41869 05-02
3 관리자 27584 05-02
4 관리자 42551 05-02
5 관리자 38179 05-02
6 관리자 32229 05-02
7 관리자 34050 05-02
8 관리자 32783 05-02
9 관리자 31653 05-02
10 관리자 34403 05-02
11 관리자 30145 05-02
12 관리자 52568 05-02
13 관리자 39101 05-02
14 관리자 35545 05-06
15 관리자 26600 05-06
16 관리자 25878 05-06
17 관리자 30244 05-06
18 관리자 26503 05-07
19 관리자 40771 05-07
20 관리자 46971 05-07
21 관리자 35773 05-07
22 관리자 36042 05-07
23 관리자 36545 05-28
24 관리자 46417 05-28
25 관리자 35529 05-28
열람중 관리자 38638 06-04
27 관리자 37882 06-11
28 관리자 37185 06-12
29 관리자 36041 12-21
30 관리자 27432 12-25
GNUBOARD_M
Copyright © JBMPA.com All rights reserved.