
이 글은 Trio의 nursery 구조가 동시 작업을 부모 작업의 수명 안에 묶어, 작업 종료와 자원 정리, 오류 전파를 다루는 방식을 설명한다. 글의 주장은 스레드 생성이나 콜백 등록처럼 호출 뒤에도 작업이 독립적으로 이어지는 방식은 제어 흐름을 파악하기 어렵게 하므로, nursery 같은 구조적 동시성으로 대체해야 한다는 것이다.
Trio에서는 nursery를 연 뒤 그 안에서 동시 작업을 시작한다.
async with trio.open_nursery() as nursery:
nursery.start_soon(myfunc)
nursery.start_soon(anotherfunc)
nursery 블록은 안에서 시작한 작업이 모두 끝날 때까지 종료되지 않는다. 따라서 함수가 반환하면 그 함수가 시작한 작업도 끝났다고 볼 수 있고, 블록 안에서 연 파일 같은 자원을 작업이 계속 사용하는 상태로 블록이 먼저 끝나는 상황을 막을 수 있다. 자식 작업에서 처리되지 않은 예외가 발생하면 Trio는 같은 nursery의 다른 작업을 취소하고 종료를 기다린 뒤 예외를 부모 작업으로 다시 전달한다.
글은 이 방식을 goto와 비교한다. 임의 위치로 흐름을 옮기는 goto가 함수 단위의 추론을 어렵게 하듯, 배경 작업을 시작하는 ‘go 문’도 함수가 반환한 뒤 작업이 남아 있는지 소스 전체를 살펴야 알 수 있다는 설명이다. 스레드 생성, 콜백, 퓨처와 프라미스도 작업을 호출자와 별도로 실행한다는 점에서 같은 문제를 만든다고 주장한다.
nursery 안에서 동적으로 작업을 추가할 수도 있다. 예를 들어 서버가 연결을 받을 때마다 처리 작업을 시작할 수 있다. 다만 함수가 nursery 객체를 명시적으로 전달받으면 그 안에 작업을 추가할 수 있으므로, 작업을 함수 수명 밖으로 분리하는 것이 완전히 불가능한 것은 아니다. 이때도 작업은 전달된 nursery의 수명에 묶인다.
글은 Trio의 취소와 예외 전파가 작업을 트리 형태로 묶는 구조에 기대며, 다른 동시성 라이브러리보다 취소를 다루기 쉽고 안정적이라고 주장한다. 다만 실제 사용 경험이 쌓여야 설계가 충분히 검증될 것이라고 덧붙인다. Happy Eyeballs 알고리즘 구현 사례도 제시하지만, 더 짧고 빠르게 작성했다는 비교는 글에 담긴 작성자의 경험이지 독립적으로 검증된 결과는 아니다.
댓글 (0)
로그인하면 이 기사에 내 생각을 남길 수 있어요