🎮 Unity에서 비동기 Task 처리하기 – WhenAny
, WhenAll
완벽 정리
Unity에서 비동기 로딩을 하다 보면
"여러 개의 에셋을 비동기로 불러오고, 완료된 순서대로 처리하고 싶다!"
혹은
"전부 로딩될 때까지 기다렸다가 시작하고 싶다!"
이런 상황이 자주 생기죠?
이럴 때 아주 유용한 것이 바로 Task.WhenAny()
와 Task.WhenAll()
입니다.
☝️ Task.WhenAny – 가장 먼저 끝나는 작업만 기다리기
개념
Task.WhenAny(params Task[] tasks)
는 여러 개의 Task 중 가장 먼저 완료된 하나의 Task가 반환되도록 기다립니다.
Task<int> task1 = SomeAsyncOperation1();
Task<int> task2 = SomeAsyncOperation2();
Task<int> task3 = SomeAsyncOperation3();
Task<Task<int>> whenAnyTask = Task.WhenAny(task1, task2, task3);
Task<int> completedTask = await whenAnyTask;
int result = await completedTask;
whenAnyTask
는 가장 먼저 끝난Task<int>
를 감싸는 Task의 Task- 결과를 얻기 위해선 한 번 더 await이 필요합니다
💡 실전 예제 – 에셋 로딩: 먼저 끝난 것부터 처리
public async void Load(List<string> assetNames)
{
List<Task<GameObject>> loadTasks = new List<Task<GameObject>>();
foreach (string name in assetNames)
{
loadTasks.Add(LoaderModule.LoadAssetAsync(name));
}
while (loadTasks.Any())
{
Task<GameObject> finished = await Task.WhenAny(loadTasks);
loadTasks.Remove(finished);
GameObject result = await finished;
if (result != null)
{
Debug.Log($"로딩 완료: {result.name}");
}
}
}
✅ 설명
- 에셋 이름 리스트를 순회하며
Task<GameObject>
리스트를 만듭니다 WhenAny
로 가장 빨리 로딩된 에셋부터 처리- 완료된 작업은
Remove()
로 제거 → 남은 것 계속 대기
✌️ Task.WhenAll – 모두 끝날 때까지 기다리기
개념
Task.WhenAll(params Task[] tasks)
는 모든 작업이 완료될 때까지 기다립니다.
Task<int> task1 = SomeAsyncOperation1();
Task<int> task2 = SomeAsyncOperation2();
Task<int> task3 = SomeAsyncOperation3();
await Task.WhenAll(task1, task2, task3);
int result1 = await task1;
int result2 = await task2;
int result3 = await task3;
Task.WhenAll()
자체는 완료 시점을 기다릴 뿐, 결과를 바로 주진 않습니다- 각 Task의 결과는 별도로
await taskX
로 받아야 합니다
🧪 Unity 에셋 로딩에 적용하면?
public async void LoadAll(List<string> assetNames)
{
var loadTasks = assetNames.Select(name => LoaderModule.LoadAssetAsync(name)).ToList();
await Task.WhenAll(loadTasks);
foreach (var task in loadTasks)
{
GameObject result = await task;
if (result != null)
Debug.Log($"완료된 오브젝트: {result.name}");
}
}
- 모든 에셋이 완전히 로딩된 후 처리
- 타이틀 화면 → 에셋 다 불러온 후 게임 시작 등에 적합
🎯 WhenAny vs WhenAll 요약 비교
항목 | Task.WhenAny |
Task.WhenAll |
---|---|---|
목적 | 가장 먼저 끝난 작업 처리 | 모든 작업 완료 대기 |
처리 방식 | 빠른 순서대로 하나씩 | 전부 끝난 후 한꺼번에 |
사용 예시 | 에셋을 빠른 순서로 인스턴스화 | 모든 리소스가 준비될 때까지 대기 |
반환값 | 완료된 하나의 Task | 모든 Task의 완료 보장 |
🚨 주의할 점
WhenAny()
는 한 Task만 반환합니다. 리스트에서 제거 후 반복해야 전체를 순서대로 처리할 수 있어요.WhenAll()
은 하나라도 예외가 발생하면 전체 Task 실패로 처리되니 try-catch로 감싸는 것도 고려하세요.
✅ 마무리
Unity에서 Task.WhenAny
와 Task.WhenAll
을 활용하면,
비동기 에셋 로딩을 더 유연하게 제어할 수 있습니다.
복잡한 상황에서도 효율적으로 비동기 흐름을 관리할 수 있는 강력한 도구죠!