- 나이 : 96년생
- 특이사항 : 조금씩 늙어가고 있음
- 좋아하는 음식 : 햄부기, 치킨, 고기
🥷기술
🐱 우리집 고양이 소개


- 이름 : 콜라
- 나이 : 14년생
- 종 : Nado moreum
📱 개인 프로젝트
🏢 참여한 프로젝트
🌱 내 잔디밭
MEC(More Effective Coroutines) 본문
| MEC (More Effective Coroutines)
MEC 에셋은 코루틴 강화버전(?) 같은 에셋 입니다.
기존 코루틴과 거의 유사한 구조로 호출 가능하면서도 성능은 더 좋습니다.
그리고 기존 코루틴에서 할 수 없던 여러가지 기능들이 지원됩니다.
| 기본 코루틴과 MEC 기능 비교
기본 코루틴 | MEC 무료 버전 | MEC 프로 버전 | |
빈 코루틴 10만 개 실행 시간 |
~110.53 | ~9.62 | ~9.64 |
싱글톤 인스턴스로 코루틴 실행 가능 |
✗ | ✗ | ✓ |
코루틴에 딜레이 걸기 특정 주기로 코루틴 걸기 코루틴 계속해서 호출 |
✗ | ✓ | ✓ |
GameObject 인지 아닌지에 따라서 코루틴을 중단 가능 |
✗ | ✓ | ✓ |
멀티스레드에 안전 | ✗ | ✓ | ✓ |
코루틴 일시중지 및 이어서 실행하기 | ✗ | ✓ | ✓ |
Late Update | ✗ | ✓ | ✓ |
Slow Update | ✗ | ✓ | ✓ |
Realtime Update | ✓ | ✗ | ✓ |
Editor Update | ✗ | ✗ | ✓ |
End Of Frame | ✓ | ✗ | ✓ |
Manual Timeframe | ✗ | ✗ | ✓ |
코루틴을 직접 제어 가능 | ✗ | ✗ | ✓ |
연결된 코루틴 동시에 멈추게 하기 | ✗ | ✗ | ✓ |
함수가 true 를 반환할 때 까지 지연 가능 | ✗ | ✗ | ✓ |
| 기존 코루틴에서 전환하기
기존 코루틴을 사용할 때 호출하던 IEnumerator 를 반환하는 메소드들을 IEnumerator<float> 을 반환하는 형식으로 바꿉니다.
기존 코루틴 메소드 :
private IEnumerator CoroutineProcess()
{
// Case 0
yield return null;
// Case 1
yield return new WaitForSeconds(2.0f);
}
MEC 코루틴 메소드 :
private IEnumerator<float> CoroutineProcess()
{
// Case 0
yield return Timing.WaitForOneFrame; // yield return 0; 과 동일
// Case 1
yield return Timing.WaitForSeconds(2.0f);
}
케이스별로 MEC 에서 변경된 형식을 제공합니다.
코루틴을 실행할 때는 다음과 같은 형식으로 호출하면 됩니다.
// 1. 일반적인 코루틴과 동일하게 Update 시점에서 에서 동작
Timing.RunCoroutine(CoroutineProcess());
// 2. FixedUpdate 동작
Timing.RunCoroutine(CoroutineProcess(), Segment.FixedUpdate);
// 3. LateUpdate 동작
Timing.RunCoroutine(CoroutineProcess(), Segment.LateUpdate);
// 4. SlowUpdate 동작
Timing.RunCoroutine(CoroutineProcess(), Segment.SlowUpdate);
인자 Segment 를 지정하지 않으면 기본적으로 Segment.Update 로 설정됩니다.
Timing.RunCoroutine(CoroutineProcess().CancelWith(gameObject));
위와 같이 CancelWith 와 함께 사용하면 지정한 게임오브젝트가 비활성화 되거나 null 이 되면 코루틴도 함께 중단됩니다.
때문에 씬이 전환되거나 했을때 오브젝트가 비활성화 되는 등의 상황을 고려해서 CancelWith 를 항상 의식해서 사용하면 좋습니다.
| 코루틴 일시중지 및 이어서 실행하기
// Pause
Timing.PauseCoroutines(gameObject);
// Resume
Timing.ResumeCoroutines(gameObject);
Timing.PauseCoroutines, Timing.ResumeCoroutines 메소드를 이용해서 일시정지 및 재개가 가능합니다. 대상은 코루틴을 핸들링 하는 핸들러가 되어야 합니다. 예를들면 게임오브젝트가 될 수도 있지만 MEC 설정 가능한 코루틴의 태그로 지정할수도 있습니다.
| WaitUntilDone
유니티에서 기존 코루틴에서 중간에 또 다른 코루틴이나 비동기 작업을 기다리게 하기 위해 yield return (어떤 변수 or 함수) 형태로 구문이 들어가는 경우가 종종 있습니다. MEC 에서도 WaitUnitilDone 메소드를 호출하면 이런 작업이 가능합니다.
private IEnumerator<float> OtherCoroutine()
{
yield return Timing.WaitForOneFrame;
}
private IEnumerator<float> CoroutineProcess()
{
yield return Timing.WaitUntilDone(OtherCoroutine());
}
위와 같은 형태로 다른 코루틴이 끝날 때 까지 기다릴 수 있습니다.
yield return Timing.WaitUntilTrue(functionDelegateThatReturnsBool);
yield return Timing.WaitUntilFalse(functionDelegateThatReturnsBool);
위와 같이 WaitForUntilTrue, WaitForUntilFalse 를 이용하면 인자로 전달한 딜리게이트의 반환 값이 true 혹은 false 가 될 때 까지 대기시킬 수도 있습니다.
| SlowUpdate
SlowUpdate 는 기존 유니티에는 없는 컨셉이고, MEC 에서 만든 컨셉입니다. '거의' 매 프레임에 실행되어야 하지만 그렇다고 정말 매 프레임 실행시킬 필요까지는 없는 작업을 할 때 좋습니다. 예를 들면, UI 의 어떤 텍스트 값을 변수 값에 따라 갱신되게 하고 싶은 경우라면 좋은 예시가 됩니다. SlowUpdate 는 1초에 7번 호출 되기 때문에 Update 보다 호출이 적어 퍼포먼스에 유리합니다.
Timing.Instance.TimeBetweenSlowUpdateCalls = 3f;
물론 7초가 아닌 3초로 간격을 바꾸고 싶으면 위와 같이 코드를 통해 변경할 수 있습니다.
| 태그 (Tags)
코루틴을 실행시킬 때, 코루틴 마다 태그를 달아서 관리할 수 있게됩니다.
void Start()
{
Timing.RunCoroutine(CoroutineProcess(), "Tag1");
Timing.RunCoroutine(OtherCoroutine(), "Tag2");
Debug.Log($"Killed : {Timing.KillCoroutines("Tag1")}");
}
위와같이 RunCoroutine 할 때 태그를 설정하고, 해당 태그를 가진 모든 코루틴을 중단하거나 할 때 사용할 수 있습니다.
| LocalTime
MEC 에는 유니티에 없는 컨셉인 SlowUpdate 가 있는데, SlowUpdate 세그먼트에서 동작하는 코루틴은 Time.deltatTime 이 의도대로 동작하지 않습니다. (7초에 1회 호출되기 때문에..) 그래서 MEC 코루틴 안에서는 Time.deltatTime 보다는 Timing.LocalTime 을 사용해야 어느 세그먼트에 동작하던 원하는 의도대로 동작시킬 수 있습니다.
| 추가적인 함수들
- CallDelayed : 원하는 시간(초) 만큼 기다렸다가 호출합니다.
- CallContinously : 원하는 시간(초) 동안 호출합니다.
- CallPeriodicaaly : 원하는 시간(초) 동안 x 초 마다 주기적으로 호출합니다.
| CallDelayed
Timing.CallDelayed(3f, () => {
Debug.Log("3초 후 실행");
});
| CallContinously
Timing.CallContinuously(3f, () =>
{
Debug.Log("3초 동안 실행");
});
| CallPeriodicaly
Timing.CallPeriodically(3f, 1.5f, () =>
{
Debug.Log("3초 동안 1.5 초 간격으로 호출");
});
| 메소드 체이닝 구조로 호출하기
// 일반적인 MEC 호출
Timing.RunCoroutine(CoroutineProcess(2f).CancelWith(gameObject));
// 유동적인 구조로 호출
CoroutineProcess(2f).CancelWith(gameObject).RunCoroutine();
MEC 문서에서는 Fluid Architecture (유동적인 아키텍쳐) 라고 설명하고 있지만, 쉽게 말하면 메소드 체이닝을 활용해서 위와 같이 메소드를 호출 할 수 있습니다.
※ 현재 완전 비추천 에셋입니다...! 좀 귀찮은 버그가 있는데, MEC 코루틴 함수 내에 WaitUntil 계열의 메소드에 람다 사용시 CancelWith로 게임 오브젝트를 전달하더라도 오브젝트가 활성화되지 않은 상태에서도 계속 람다 함수가 호출됩니다. (아마도 코루틴 내 StartCoroutine을 따로 호출한 것과 동일하게 동작하는 것 같음) -> 이 동작 방식으로 인해 예상치 못한 버그가 발생하기 좋기 때문에 사용을 비추천 합니다. 기본 코루틴을 쓰거나 UniTask를 대안으로 사용하는것이 좋아 보입니다.