ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 파이썬의 코루틴
    Python/study 2013. 12. 18. 02:53

    ※ 주의사항

    아래 공격 코드는 연구 목적으로 작성된 것이며, 허가 받지 않은 공간에서는 테스트를 절대 금지합니다.

    악의 적인 목적으로 이용할 시 발생할 수 있는 법적 책임은 자신한테 있습니다. 이는 해당 글을 열람할 때 동의하였다는 것을 의미합니다.

    해당 문서의 저작권은 해당 저자에게 모두 있습니다. 다른 용도로 사용할 시 법적 조치가 가해질 수 있습니다.


    이번에는 코루틴에 대하여 알아보도록 하겠습니다.


    코루틴이 무엇이냐? 생소한 단어라 먼저 사전적의미를 찾아보았습니다. 

     

    코루틴 [coroutine]

    프로그램에서 순서는 일반적으로 불려지는 쪽이 부르는 쪽에 속하고 있는 것이 대부분이지만 어느 쪽도 종속 관계가 아니라 대등한 관계로 서로 호출하는 것이다. 예를 들면, 게임 프로그램에서 각 플레이어 루틴은 서로 코루틴된다. 복수 프로세스 간에서 한정된 형태의 통신을 행하는 프로그램을 순차 제어로 실현한 것으로 볼 수도 있다.

    - 1차 출처 컴퓨터인터넷IT용어대사전, 전산용어사전편찬위원회 엮음, 2011.1.20, 일진사

    - 2차 출처 : 네이버 지식백과

    그렇습니다. 여기서 눈여겨 볼 부분은 어느쪽도 종속 관계가 아니라 대등한 관계로 서로 호출하는 것이라는 부분입니다. 일반적으로 함수에서 다른 함수를 호출하면 호출을 한 함수를 Caller, 호출 당한 함수를 Callee라고 하여 서로 종속적인 관계로 봅니다. 왜냐하면 Callee가 모든 동작을 마치고 Caller에게 결과를 갖다 바치기(?) 때문입니다.


    그런데, 코루틴은 그렇지 않습니다. 코루틴이 될 함수를 깨우기위해서는 어쩔 수 없이 현재의 함수에서 코루틴이 될 함수를 호출해야하만 합니다. 그렇다고해서 이 둘의 관계가 종속적인지 아닌지는 아직 알 수 없습니다. 코루틴은 순차적으로 서로를 호출하면서 제어권을 주고 받습니다. 마치 다음 노래가사처럼 말입니다.


    할머니 : 영감

    할부지 : 왜불러

    할머니 : 뒷 뜰에 뛰어놀던 병아리 한쌍을 보았소

    할부지 : 보았지

    할머니 : 어쨌소

    할부지 : 이 몸이 늙어서 몸보신 할려고 먹었지

    할머니 : 잘했군 잘했어

    (후략)                                       - 하춘화, 잘했군 잘했어 가사 中

    위와 같이 할머니가 질문(요청)을 하면 할아버지가 대답(응답)을 하는 식으로 주고 받는 대화의 흐름과 코루틴의 흐름은 아주 유사합니다. 코루틴의 동작은 정말 간단하게 설명하면 입력 값을 요청하고, 입력 값을 넣어준다는 간단한 흐름의 반복 형태를 가지고 있습니다.  코루틴이 데이터 입력을 요청하면, 코루틴을 호출한 함수가 입력할 데이터 값을 전달해줍니다. 서로 요청과 응담을 주거니 받거니 하는 것입니다. 


    정리 54) 코루틴 : 종속적이지 않고 서로 대화하는 형식의 함수입니다.


    코루틴의 흐름을 그림으로 살펴보면 다음과 같습니다.



    알아두셔야 할 것은 코루틴 내에는 입력을 코루틴을 부른 함수로부터 입력을 받아야 하는 지점이 있다는 것입니다. 해당 입력지점을 기준으로 코루틴과 코루틴을 호출한 함수 사이의 제어권이 순차적으로 주거니 받거니 하며 넘어갑니다. 이에서 코루틴을 이용한 예제를 보도록 하겠습니다. 해당 예제는 코루틴을 이용해 작성한 업다운 게임입니다.


    예제를 알기 위해서 해당 게임의 룰을 간략히 설명하도록 하겠습니다. 이 게임은 술래와 플레이어로 이루어집니다. 먼저 술래가 임의의 숫자를 뽑습니다. 그러면 플레이어는 술래가 뽑은 숫자를 맞추는 것입니다. 이때, 플레이어가 임의의 숫자를 부르면 술래는 자신이 뽑은 숫자와 비교하여, 플레이어가 부른 숫자가 자신이 뽑은 숫자보다 크다, 작다라는 정보만을 알려줍니다. 

     

    즉, 술래가 자신이 뽑은 숫자와 비교할 데이터를 입력할 것을 플레이어에게 요청하고, 플레이어가 데이터를 입력하는 형식입니다. 이어서 예제를 보도록 하겠습니다.


     

    위의 소스코드는 코루틴이 될 함수를 작성한 코드입니다. 각각의 라인을 순차적으로 설명드리도록 하겠습니다.


    def game(name):

    print "Hi, "+name

    print "Condition : 0 < num < 101"

    코루틴은 기본적으로 함수이기때문에 먼저 함수를 선언합니다. 해당 코루틴의 이름은 game이며, 파라미터로 name이라는 문자열 정보를 받습니다. 그리고 코루틴이 처음 실행될 때, name에 저장된 문자열을 이용하여 "Hi, 누구누구"와 같은 형태로 메시지를 출력합니다. 이어 게임의 조건을 출력합니다. 해당 조건은 술래가 뽑은 숫자는 1부터 100까지의 숫자 중 하나라는 것입니다.


    num = random.randrange(1,101)

    술래가 임의의 숫자를 뽑는 부분입니다. 가장 처음에 import한 파이썬 random 모듈의 randrange() 함수를 사용하여 1부터 100중 하나의 숫자를 추출하여 num이라는 공간에 저장합니다. num이 바로 술래가 뽑은 숫자가 되는 것입니다.


    while True:

    OoC = (yield)

    술래가 숫자를 뽑고나면 무한루프가 발생됩니다. 그리고 while문에 들어서자마자 yield 문이 보입니다. 그런데 yield 문에 공간의 이름이 명시되어 있지 않습니다. 왜 그럴까요? 여기가 바로 코루틴의 핵심입니다. 생성기의 경우에는 'yield n' 과 같은 형태로 소스코드를 작성하여 해당 yield문을 만났을 때, 함수를 일시정지하고 yield문으로 나타낸 공간에 저장된 값을 생성기를 호출한 함수로 반환하였습니다. return의 개념으로 yield문이 사용된 것입니다. 

     

    그런데, 코루틴에서는 전혀 다른 의미로 사용됩니다. 위와 같이 'OoC = (yield)' 와 같은 형태로 소스코드를 작성하면 yield문을 만났을 때, 함수를 일시정지하는 것 까지는 생성기와 같습니다. 하지만, 다음 동작으로 데이터를 반환하는 것이아니라 데이터를 입력받습니다. 이 부분에서 함수가 일시정지하면 제어권은 코루틴을 호출한 함수로 넘어가게되는데, 제어권이 넘어가면 코루틴을 호출한 함수에서는 특정 명령을 이용하여 코루틴으로 데이터를 넘겨줍니다. 코루틴은 넘겨받은 데이터를 yield문과 함께 쓰인 OoC라는 공간에 저장합니다. 그리고 다음 yield문을 만날 때 까지 즉, 데이터의 입력을 필요로 하는 지점이 나타날 때까지 동작합니다.

     

    정리 55) OoC = (yield) : 코루틴에서 사용되는 yield문은 리턴의 목적이 아니라 입력의 목적으로 사용됩니다.

     

    if OoC < 0 or OoC > 100:

    print "Wron Number!"

    elif OoC > num:

    print "Object of Comparaison is bigger than num."

    elif OoC < num:

    print "Object of Comparaison is smaller than num."

    else:

    print "Good! Num is ",+num

    While문에 들어와서 데이터를 입력받으면, 위와 같이 num과 비교하여 입력받은 데이터인 OoC가 범위를 벗어난 숫자인지, num보다 큰지, 작은지 혹은 num과 일치하는지를 따져 각각에 맞는 메시지를 출력합니다. 메시지를 출력하고 나면 다시 while문의 처음으로 돌아가기 때문에 yield문을 만나게 되고, 데이터의 입력을 기다립니다. 

     

    즉, 이 코루틴은 데이터를 입력받고 조건을 따져 메시지를 출력하고 다시 또 데이터를 입력받고 조건을 따지고 하는 동작을 반복하는 함수인 것입니다. 그럼 이제 해당 코루틴을 사용하는 예제를 보도록 하겠습니다.


     

    >>> from haerakai import game

    해당 부분은 파일로 저장된 코루틴을 사용하기 위해 haerakai라는 모듈로부터 game이라는 함수를 불러와 사용하겠다는 명령입니다. 이부분은 다음에 다루도록 하겠습니다.


    >>> name = "haerakai"

    >>>

    >>> cortn = game(name)

    코루틴의 파라미터로 넘겨줄 문자열 "Haerakai"를 name이라는 공간에 저장합니다. 그리고 코루틴 함수를 나타낼 공간을 지정하여 이후 함수명 대신 해당 공간의 이름을 사용합니다. 여기서는 cortn이 함수를 나타내는 이름으로 사용됩니다. coroutine이라는 이름을 나름 줄인 것인데 알아채셨을지 모르겠습니다.


    >>> cortn.next()

    Hi, haerakai

    Condition : 0 < num < 101

    >>>

    이제는 함수를 호출합니다. next()함수를 사용하여 cortn이라는 공간이 가리키는 함수 즉, game(name)을 호출합니다. 이것은 코루틴을 사용할 때, 가장 먼저해야될 명령입니다. 왜냐하면 코루틴 내의 처음 시작부터 첫번째 yield문까지의 소스코드를 실행하여 코루틴이 데이터를 입력받기위해 대기하도록 해야 다음 진행이 가능하기 때문입니다.


    정리 56) cortn.next() : 코루틴을 호출한 직후 next()함수를 사용하여, 코루틴의 첫번째 yield 문까지를 동작하게 합니다.


    여기서는 cortn.next()라는 명령을 주어 첫번째 yield문까지를 실행하였습니다. 그 결과로 코루틴의 시작과 첫번째 yield문 사이에 있는 환영메시지와 게임의 조건을 말하는 메시지가 출력되었습니다.


    >>> cortn.send(50)

    >>> ...(생략)

    앞에서 next()함수를 사용하였기 때문에 코루틴은 데이터 입력을 받기위한 대기상태로 접어들었습니다. 이제부터는 send() 함수를 사용하여 코루틴으로 데이터를 입력해주면 됩니다. 코루틴 내에서 yield 문을 만나 코루틴이 데이터를 입력받기위해 대기상태에 들고 제어권이 코루틴을 호출한 함수로 넘어오면, 사용자는 코루틴으로 데이터를 입력해주어야 합니다. 이때, send()함수를 사용하여 데이터를 입력해주는 것입니다.


    위에서는 cortn.send(50)이라는 명령을 주어 코루틴으로 50이라는 데이터를 입력해주었습니다. 50이라는 데이터를 입력받은 코루틴은 yield문 이후의 소스코드를 실행합니다. 여기서는 앞서보았던 조건문들을 수행합니다. 그 결과로 send()함수를 통해 입력받은 데이터 50은 num보다 크다는 메시지를 출력해줍니다. 


    정리 57) cortn.send(50) : 코루틴에 데이터를 입력할 때에는 send()함수를 사용합니다.


    이후 코루틴은 다시 yield 문을 마주함으로써 데이터를 입력받기위한 대기상태에 들게 됩니다. 이때마다 send()함수를 사용하여 데이터를 입력해주면 됩니다.


    >>> cortn.close()

    마지막으로 코루틴을 종료할 때에는 close()함수를 사용하면 됩니다. 코루틴은 특별한 리턴없이 계속되는 입력에 대한 처리만을 하는 용도로 사용할 수 있습니다. 이러한 경우 코루틴을 종료하기위해서 코루틴을 호출한 함수에서 close()함수를 사용하면 됩니다. ( 위의 그림에는 빠졌습니다. )

     

    정리 58) cortn.close() : 코루틴을 종료할 때에는 close()함수를 사용합니다.

     

    이렇게 코루틴에 대한 개념과 코루틴을 사용하는 방법에 대하여 알아보았습니다.

     

     

    정리모음

    정리 54) 코루틴 : 종속적이지 않고 서로 대화하는 형식의 함수입니다.
    정리 55) OoC = (yield) : 코루틴에서 사용되는 yield문은 리턴의 목적이 아니라 입력의 목적으로 사용됩니다.
    정리 56) cortn.next() : 코루틴을 호출한 직후 next()함수를 사용하여, 코루틴의 첫번째 yield 문까지를 동작하게 합니다.
    정리 57) cortn.send(50) : 코루틴에 데이터를 입력할 때에는 send()함수를 사용합니다.
    정리 58) cortn.close() : 코루틴을 종료할 때에는 close()함수를 사용합니다.

    참고 URL 및 도서

    - 파이썬 완벽 가이드, 데이비드 M. 비즐리 저, 2012년, 인사이트 펴냄

    http://pyengine.blogspot.kr/2011/07/python-coroutine-1.html


    'Python > study' 카테고리의 다른 글

    파이썬의 모듈  (0) 2013.12.18
    파이썬의 예외처리  (0) 2013.12.18
    파이썬의 객체와 클래스  (0) 2013.12.18
    파이썬의 제네레이터(추가)  (0) 2013.12.18
    파이썬의 제네레이터와 이더레이터  (8) 2013.12.18
    파이썬의 함수  (0) 2013.12.18
    파이썬의 반복문  (0) 2013.12.18
    파이썬의 파일 입출력  (0) 2013.12.18
    파이썬의 조건문  (0) 2013.12.18
    파이썬의 자료형 - 사전  (0) 2013.12.18
Designed by Tistory.