Coroutine 간략한 정리

CJB_ny·2021년 11월 17일
1
post-thumbnail

Unity를 학습하는데 있어서 "Coroutine"이라는 개념은 많이 중요하다.
많이 사용하기도하고 컨텐츠 제작이 거의 무조건 필요하다고 보면 될 것이다.

Coroutine을 구글링한다면은 거의 유니티와 연관된 내용이 나올것인데, 코루틴이 유니티에서 만들어진것이라고 오해사는 사람들이 가끔있는데

코루틴은 Csharp에서 지원하는 기능이다. 이를 유니티에서 함수화 해서 사용자들이 사용하기 편하게 함수들을 만들어 놓은 것 뿐이다.
(참고로 C++에서는 코루틴을 지원하지 않는다)

아무튼,

1. Coroutine?

어디에 사용하고 무엇인지 한번 살펴보자.

예를들어 엄청 복잡한 로직을 실행한다고 가정을 해보자.
A*(에이스타) 나 복잡한 길찾기 같은 알고리즘을 실행한다고 했을 때
이 연산을 1/60 초(60프레임의 1틱)만에 다 연산을 할 필요는 없다.

만약 1/60초만에 연산을 끝내지 못하고 좀더 오래 걸렸다라고 하면은 프레임이 밀려 뚝뚝 끊기는 렉 현상이 발생 할것이다.

그래서 매프레임마다 연산을 해서 연산했던 부분을 기억했다가 정지후 그 다음프레임에서 다시 연산을 하고 이런식으로 하면 좋을거 같다라는 생각이 든다.

그래서 프레임마다 끊어서 연산을 하면 좋을거같은데..
기존의 기초적인 Csharp문법으로는 이것을 구현하기가 매우 힘들다.

만약 이렇게 i 를 밖으로 빼내와서 만번째마다의 i를 기억을 해서
다시 실행시키는 방법을 구현한다고 하더라도
이러한 경우가 수백 수십가지로 늘어나면
일시정지를 했다가 다시 코드를 실행 시키는 작업이 매우 힘들 것이다.

그래서 그냥 프로그래밍 기능상 일시 정지를 했다가
다음 틱에서는 VeryComplicated함수를 계속 실행을 할 수 있게(우리가 딱 정지 시킨 지점에서)

다시 재생시킬 수 있다면 굉장히 편할거 같다는 생각이 든다.

이것이 바로 Coroutine 의 개념이다

잠깐 정리하자면,
일시정지를 시켰다가. 신기하게도 일시정지 시킨 그 지점에서 모든 값들을 똑같이 복원된 상태로
다시 한번 딱! 하고 바로 start해줄 수 있다. == 다시 복원을 시킬 수가 있다. 이것이 바로 코루틴 개념이다.

2. Coroutine 사용

그래서 이것을 어떻게 사용하는 지 한번 보도록하자
코루틴을 사용하러면 IEnumerator라는 인터페이스를 받아서 사용해야하는데

2-1 yield

이렇게 IEnumerator를 받아주고
return을 할 때는 항상 앞에 yield를 붙여줘야한다.

그리고 코드를 대충

이렇게 짜주고

Test의 객체를 아래사진처럼 하나 만들어 주자

그리고 foreach를 통해 어떤 값을 출력하는지 보도록하자

그러면 1, 2, 3, 4 가 순서대로 잘 찍히는 것을 볼 수가 있다.

그런데 이상한 점이 우리는 반환 타입을 IEnumerator로 해주었는데
우리는 분명 정수를 return 하였음에도 에러는 없었다.

foreach(var t in test)로 하고 var에 마우스를 갖다 대면

system.object타입인것을 볼 수 잇는데
system.object은 Csharp에서 거의 모든 오브젝트들의 슈퍼 조상님같은 존재이다.

그래서 위의 사진은 박싱과 언박싱의 개념을 우리가 사용한것이다.
원래 대로라면

이상태에서 우리가 캐스팅을 해준것이된다.

따라서 yield는 return을 하는 타입이 정수형이든 string이든 클래스든 뭐든 가능하다는것이다.
(여기서 클래스를 반환가능 하다는 점이 중요하다 => 이를 응용해서 컨텐츠 제작함)


여기서에서 object타입을 뱉는 것을 확인 하였으니까

CoroutineTest()를 실행하면 return 값이 Test가 될테니

Test value = (Test)t; 로 이렇게 형변환 하고

value가 Test타입으로 반환이 될것이다.


여기서 이렇게 id도 추출 할 수 있다는 생각이 든다.

그리고 아무것도 반환하고 싶지 않다면
yield return null;을 사용하여도된다.

2-2 종료하고싶을 때

return null한 부분에서 멈추고 싶다면 어떻게 해야할까??

우리는 예전에는 그냥 함수에서 return 을 쓰면 종료가 되는데

지금은 코루틴에서 return 을 일시정지하는데에 썻다.

그렇다는 것은 진짜 영구적인 종료도 있을텐데

그것은 바로

그러면 밑줄이 뜨면서 에러가 나는데

밑에 코드는 쓸데없는 것이라고 불평을 하는 부분이다.

아무튼 break를 사용한다면 바로 종료 시킬 수가 있다.
(일반적인 함수에서는 그냥 return 으로 종료를 하였다.)

2-3 yield활용

우리가 무조건 yield return 이런식으로 사용해야 하는것이 아니라

for문 중간에도 사용을 하여 등장 시킬 수도 있다.

백만번을 열심히 열심히 돌다가 만약에 i가 10000으로 나뉜다면, 즉 10000번째마다 쉬고 싶다라는 얘기가 되는건데.

yield return null이든 뭐든 한번 쉬어 주면 될것이다.

이런식으로 일시정지를 시켜준다음에 ⇒ 그다음에 어떻게 되냐면은

이런식으로 코드가 있다고 하였을때,
GetEnumerator()함수를 빼져나와서 한번 쉰다음에

init()함수안의 test에서 foreach문 안에서

Test value = (Test)t;

Debug.Log(value.id); 이녀석에게 차례의 소유권이 넘어갈 것이다.

그래서 저기서도..뭐.. if문이나 다른것을 써가지고 계속 go(실행을)할지 멈출지 조건을 또 걸어주면 되겠다.

어쨋든 만번째마다 쉬고싶다라는것을 굉장히 간단하게 구현을 할 수가 있었다.

3. Coroutine 최종사용(+개념)

코루틴을 정리하자면
1. 함수의 상태를 저장 or 복원 가능!
그렇다면 언제 쓰는가?
-> 엄청 오래 걸리는 작업을 끊거나
-> 원하는 타이밍에 함수를 잠시 Stop / 복원하는 경우
2. return -> 우리가 원하는 타입으로 return 가능 (class도 가능)

이렇게 두가지로 정리 할 수 있다.

3-1 코루틴 자체 의미

만약 게임 서버를 개발한다고 치자
몬스터를 잡아서 아이템 드롭했다라고 가정을 하면
1.아이템이 드롭되는 로직이 실행이되다가
2.DB에 저장
3.로직실행

이렇게 순서가 될것인데, 만약 DB에 저장을 하지 못했다라치면 게임세상과 DB사이의 괴리가 발생하게 되는데
이렇게 되면 온갖 에러, 문제가 발생한다.(ex 아이템이 복사가 된다던지, 강화에 성공했는데 DB에 저장을 하지 못해서 서버를 다시 열었을때 원상태로 돌아가 있다던지 등등등)

그래서 DB에 저장하는 부분을 던지고, 잠시 기다렸다가 결과물을 받아서(DB에서 성공 요청으 돌아어면)
그다음 로직을 실행하도록하면 아름답게 코드가 돌아갈 것이다.

그런데 이부분은 Csharp에서는 코루틴을 지원하기 때문에 코루틴으로 쉽게 구현이 가능하고
C++에서는 코루틴을 지원하지 않아서
위에서 설명한 대로
before, after로 상태를 나눠서 로직을 실행해야 할것이다.

그니까 C++에서는 코루틴을 지원하지 않아서 (yield return )

그래서 상태를 나눠서 코딩을 해줘야한다.

  1. 아이템 만들기
  2. DB저장 → 요청 → 요청 받기
  3. 요청 받을 때까지 멈춰있다가 요청한것 반환이 오면
  4. 로직 실행

이런식으로 해야함.

3-2 코루틴 시작, 멈춤

이제 코루틴을 시작을 시키는 방법과,
시작을 시켰는데 중간에 멈추고 싶은 경우를 코드 하나로 다 살펴보도록하자.


(함수 앞의 Co는 코루틴이라는것을 명시하기 위해 붙인것이다.)

3-3 WaitForSeconds

위의 코드에서 IEnumerator에 WaitForSeconds라는 애가 반환이 되니까

유니티 엔진 자체에서 WaitForSeconds 이녀석을 체크를 해가지고 "얘는 몇초동안 기다리는 애구나"라고 인식을 해서 그 다음부분은 우리가 넣어준 seconds후에 다시 코드를 실행하게끔 만들어 줄것이다.

⇒ 어떻게보면은 코루틴을 관리하는 중앙시스템이 있어서 우리는 그것을 사용하기만 하면된다.

3-4 최종사용

내가 10초후의 캐스팅이 되는 스킬을 채널링한다고 가정했을때
StartCoroutine을 통해서 해당 코루틴을 실행을 시켜주고(인자 값도 넣어 줄 수 있다.)

시작을 시켰는데 중간에 멈추고 싶은 경우는 만약
내가 어떤 스킬을 10초후에 "캐스팅"하기 위해서 "채널링"을 했는데
그동안 나를 누군가가 스턴을 먹여가지고 이 스킬을 종료해야하는(쓸 수 없다라는) 상황이라고 한다면은

31번째 코드줄 의 Stopcoroutine(co);를 통해서 중지를 시켜주면 된다.

StopCoroutine을 사용하기전에
17번째 줄의 코드와 같이 StartCoroutine은 Coroutine을 뱉어주기때문에
Coroutine co로 저장을 해주고(위에서 선언함)
co로 저장을 해주고

co를 사용해서 StopCoroutine(co)로 해당 코루틴을 종료 시킬 수 있다.

현재 위의 사진의 코드는 Explode Enter를 실행을 하고 4초후에 Explode Exceute!!!를 디버그 찍어내는 것인데
Explode Enter를 디버그 찍어낸후 바로
CoStopExplode 코루틴을 실행시켜 이전의 코루틴을 co를 통해서 종료를 시키는 것이다.

그러면 Explode Enter → Stop Enter → Stop Execute!! 해가지고 폭발을 안하는것을 볼 수가 있다.

3-5 끝

이렇게 해서 코루틴에 대해서 알아보았고 코루틴은 컨텐츠 작업에서 굉장히 자주 사용되고

굉장히 좋은 기능이니까 이거는 점점 익숙해 지기를 바란다!!

profile
공부 일기장으로 변해버린 블로그 (https://cjbworld.tistory.com/ <- 이사중)

0개의 댓글