ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 코루틴
    Python 2023. 10. 24. 16:29

    지금까지 함수를 호출한 뒤 함수가 끝나면 현재 코드로 돌아옴

    def add(a, b):
        print('add 함수 실행')
        c = a + b        # add 함수가 끝나면 변수와 계산식은 사라짐
        return c
    
    def clac():
        print('clac 함수 실행')
        r = add(1, 2)    # add 함수가 끝나면 다시 clac 함수로 돌아옴
        print('결과:', r)
    
    clac()
    
    # 실행 결과
    
    clac 함수 실행
    add 함수 실행
    결과: 3

    ↑ 예제, clac 함수 안에서 add 함수를 호출했을 때 add 함수가 끝나면 다시 clac 함수로 돌아옴

    add 함수가 끝나면 함수에 들어 있던 변수와 계산식은 모두 사라짐

    clac가 메인 루틴이면 add가 서브 루틴

     

    코루틴(coroutine)은 cooperative routine으로 서로 협력하는 루틴

    메인 루틴과 서브 루틴처럼 종속된 관계 X 서로 대등한 관계 O, 특정 시점에 상대방의 코드 실행

     

    코루틴은 함수가 종료되지 않은 상태에서 메인 루틴의 코드를 실행한 뒤 다시 돌아와서 코루틴의 코드 실행

    > 코루틴이 종료되지 않았으므로 코루틴의 내용도 계속 유지

     

    일반 함수를 호출하면 코드를 한 번만 실행할 수 있지만, 코루틴은 코드를 여러 번 실행 가능

    함수의 코드를 실행하는 지점을 entry point라고 하는데, 코루틴은 엔트리 포인트가 여러 개인 함수

     

    코루틴에 값 보내기

    코루틴은 제너레이터의 특별한 형태

    제너레이터는 yield로 값을 발생시켰지만 코루틴은 yield로 값을 받아 옴

    코루틴에 값을 보내면서 코드를 실행할 때는 send 메서드 사용

    send 메서드가 보낸 값을 받아 오려면 (yield) 형식으로 괄호로 묶어 준 뒤 변수에 저장

    # 코루틴객체.send(값)
    # 변수 = (yield)
    
    def number_coroutine():
        while True:        # 코루틴을 계속 유지하기 위해 무한 루프 사용
            x = (yield)    # 코루틴 바깥에서 값을 받아 옴, yield를 괄호로 묶어야 함
            print(x)
    
    co = number_coroutine()
    next(co)      # 코루틴 안의 yield까지 코드 실행(최초 실행)
    
    co.send(1)    # 코루틴에 숫자를 보냄
    co.send(2)
    co.send(3)
    
    # 실행 결과
    
    1
    2
    3

     

    send로 코루틴의 코드를 최초로 실행

    앞에서 코루틴의 코드를 최초로 실행할 때 next 함수(__next__ 메서드)를 사용, 코루틴객체.send(None)과 같이 send에 None을 지정해도 코루틴의 코드를 최초로 실행할 수 있음

     

    코루틴 바깥으로 값 전달하기

    코루틴에 숫자를 보내고, 코루틴은 받은 숫자를 누적해 바깥에 전달

    # 변수 = (yield 변수)
    # 변수 = next(코루틴객체)
    # 변수 = 코루틴객체.send(값)
    
    def sum_coroutine():
        total = 0
        while True:
            x = (yield total)    # 코루틴 바깥에서 값을 받아 오면서 바깥으로 값을 전달
            total += x
    
    co = sum_coroutine()
    print(next(co))      # 0: 코루틴 안의 yield까지 코드를 실행하고 코루틴에서 나온 값 출력
    
    print(co.send(1))    # 1: 코루틴에 숫자 1을 보내고 코루틴에서 나온 값 출력
    print(co.send(2))    # 3: 코루틴에 숫자 2를 보내고 코루틴에서 나온 값 출력
    print(co.send(3))    # 6: 코루틴에 숫자 3을 보내고 코루틴에서 나온 값 출력
    
    # 실행 결과
    
    0
    1
    3
    6

    코루틴에서 값을 누적할 변수 total를 만들고 0 할당(곱셈에서는 1 할당)

     

    next와 send의 차이

    next는 코루틴의 코드를 실행하지만 값을 보내지 않을 때 사용

    send는 값을 보내면서 코루틴의 코드를 실행할 때 사용

     

    값을 보내지 않고 코루틴의 코드 실행

    next 함수(__next__ 메서드)만 사용

     

    코루틴을 종료하고 예외 처리

    보통 코루틴은 실행 상태를 유지하기 위해 while True:를 사용해 무한 루프로 동작

    코루틴을 강제로 종료하고 싶다면 close 메서드 사용

     

    코루틴에 숫자 20개 보낸 뒤 코루틴 종료 코드

    # 코루틴객체.close()
    
    def number_coroutine():
        while True:
            x = (yield)
            print(x, end=' ')
    
    co = number_coroutine()
    next(co)
    
    for i in range(20):
        co.send(i)
    
    co.close()    # 코루틴 종료
    
    # 실행 결과
    
    0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

    close는 코루틴의 종료 시점을 알아야 할 때 사용하면 편리

     

    GeneratorExit 예외 처리

    코루틴 객체에서 close 메서드를 호출하면 코루틴이 종료될 때 GeneratorExit 예외 발생

    > 이 예외를 처리하면 코루틴의 종료 시점을 알 수 있음

    def number_coroutine():
        try:
            while True:
                x = (yield)
                print(x, end=' ')
        except GeneratorExit:    # 코루틴이 종료될 때 GeneratorExit 예외 발생
            print()
            print('코루틴 종료')
    
    co = number_coroutine()
    next(co)
    
    for i in range(20):
        co.send(i)
    
    co.close()
    
    # 실행 결과
    
    0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 
    코루틴 종료

    코루틴 안에서 try except로 GenerateExit 예외가 발생하면 '코루틴 종료' 출력

    > close 메서드로 코루틴을 종료할 때 원하는 코드 실행

    'Python' 카테고리의 다른 글

    정규표현식  (0) 2023.10.25
    데코레이터(장식자)  (0) 2023.10.25
    제너레이터(발생자)  (0) 2023.10.24
    이터레이터(반복자)  (0) 2023.10.24
    예외 처리  (0) 2023.10.23
Designed by Tistory.