루아, 유니티에서 코루틴을 써먹기만 하다가, 예전에 그냥 궁금해져서 한 번 찾아봤었다.
‘코루틴(Coroutine)’은 서브루틴보다 좀 더 일반화된 루틴이라고 볼 수 있다. 다들 알다시피 서브루틴이 자기 자신의 로직을 전부 실행 하고나면 호출자에게로 돌아간다. 하지만 코루틴은 호출자에게로 제어권이 돌아가지 않는다. 서로 다른 코루틴에게로 각자 제어권을 양보(yield) 하는 형태로 로직이 구성될 뿐. 반대로 생각하자면 서브루틴은, ‘중간에 제어권을 양보하지 않으며 할 일이 다 끝나면 무조건 호출자에게로 제어권이 반환되는 코루틴’이라고 생각할 수 있겠다.
어떤 코루틴(A)가 다른 코루틴(B)로 제어권을 양보해 준 상태에서, B에서 다시 A로 제어권이 양보된다면 코루틴A는 루틴의 처음부터 시작하는게 아니라 아까 양보해 줬던 곳에서부터 다시 시작한다. 즉 제어권을 양보하고 다시 되돌려 받는것은 코루틴을 일시정지 시켰다가 그대로 다시 시작하는것임. 호출자 입장에서 보면 함수의 진입점이 여러개인 것 처럼 볼 수 있다. 똑같은 루틴을 호출했는데 타이밍에 따라서 동작이 다를 수 있으니.
하지만 이렇게 제어권이 떠돌아다니는 코루틴은 일반적인 서브루틴과 비교해서 사람들이 다루기 어려워 했기 때문에, 루틴이 끝나면 제어권이 다시 호출자에게로 돌아오는 코루틴. 즉, ‘세미 코루틴(Semi coroutine)’의 개념을 도입했다. 세미 코루틴은 코루틴과 마찬가지로 양보하면서 일시정지, 재개가 가능하고 진입점도 여러개지만, 루틴이 끝나면 다시 호출자에게로 돌아간다. 사실 생각해보면 서브루틴에 익숙한 개발자들이 사용하기도 편리하고, 세미 코루틴에 약간의 Dispatcher만 구현하면 위의 그냥 코루틴처럼 동작하게도 할 수 있으니 좋은 방향이었던것 같다.
유니티는 개발자들에게 멀티 쓰레딩 환경을 제공해주는것 대신 게임 업데이트 루프 사이클과 맞물려 돌아가는 코루틴 스케쥴러를 만들어서 동시성 개발을 하라고 쥐어주었다. (이렇게 제공된 스케쥴러를 사용해서 코루틴을 하나의 쓰레드처럼 쓰는게 가능… 하지만 사실 진짜 쓰레드는 아니라 비선점형 스케쥴링 되어있는 코루틴들이라 어느 한 곳에서 작정하고 뺑뺑이를 돌아버리면 다른 코루틴은 앞 코루틴이 양보해주길 기다릴 수 밖에 없다..) 사실 유니티가 개발자들에게 각종 동기화 관련 문제들로 골썩이지 말라고 이렇게 한 것 같지만 게임 개발하는데 쓰레드는 필요하기 마련인지라 아쉬울 따름.
요즘은 다들 알겠지만, 예전에 유니티 도큐먼트에서 코루틴 관련 문서들을 봐도 해당 내용이 없어서 좀 오랫동안 몰랐던 것 하나. 어떤 코루틴 본문 안에서
yield return [yieldInstruction];
처럼 yield return문에 어떤YieldInstruction
을 넣으면 그YieldInstruction
이 끝날 때 까지 해당 코루틴은 대기한다. 이를 이용하면www
요청을 순차적으로 날릴 수도 있고, (요청 날리고, 응답 받고, 다음 요청 날리고..) 절차적으로 나열될 수 밖에 없는 게임 튜토리얼도 월드 규칙이 돌아가는Update()
를 건드리지 않으면서 구현하는게 가능하다. (StartCoroutine
을 할 때마다 쓰레기가 생긴다지만 적당히 메인 게임 루프를 더럽히지 않는 선에서는 나쁘지 않다고 생각함. 매번 실행하는 루틴도 아니기도하고.)
'나중에 사용 케이스들을 모아서 글을 한번 써봐야지'라고 생각만 하고 있다. 언제가 될지..
References
- Design of a separable transition-diagram compiler
- The art of computer programming, volume 1 (3rd ed.)
- Structured programming
- A Language of Coroutines
- Coroutines in Lua
'Note' 카테고리의 다른 글
C#에서 Dictionary에 Enum을 써도 괜찮은것 같다 (1) | 2019.12.23 |
---|---|
TIL: 스칼라(jvm)에서 JS코드 실행하기 (0) | 2017.10.09 |
TIL: C#에서 enum이나 struct를 Dictionary의 Key값으로 사용하면 쓰레기가 생긴다 (1) | 2017.07.06 |
TIL: docker 컨테이너안에서 ip 바인딩은 localhost가 아니라 0.0.0.0으로 해야한다 (0) | 2017.07.02 |
TIL: Unity compares Objects to null implicitly (0) | 2017.06.29 |