Unity/정보

[Unity] 유니티에서 Task 사용하기

달시_Dalsi 2025. 1. 4. 21:03
728x90

Task의 기본 개념

Task는 비동기 작업을 수행하기 위해 사용됩니다. 비동기 작업은 메인 스레드의 실행을 차단하지 않고, 병렬로 작업을 수행하거나 기다릴 수 있는 기능입니다. 이를 통해 작업이 완료될 때까지 기다리거나, 작업 완료 후의 동작을 할 수 있습니다.

 

Task의 주요 특징

  • 비동기 작업의 결과를 반환할 수 있습니다.
  • 병렬 처리를 지원합니다.
  • await를 통해 작업이 완료될 때까지 기다릴 수 있습니다.

 

Task의 기본 사용법

using System.Threading.Tasks;
using UnityEngine;

public class TaskExample : MonoBehaviour
{
    async void Start()
    {
        Debug.Log("작업 시작");

        int result = await PerformDoubleTask(5);

        Debug.Log($"결과: {result}");
    }

    private async Task<int> PerformDoubleTask(int number)
    {
        await Task.Delay(1000); // 1초 대기
        return number * 2;
    }
}

Start 메서드

  • 이 코드에서는 async를 사용하여 비동기적으로 실행되며, PerformDoubleTask를 호출합니다.

PerformDoubleTask 메서드

  • 숫자를 두 배로 만드는 비동기 작업을 정의합니다.
  • 작업: 1초 대기(Task.Delay) 후 입력값을 두 배로 계산하여 반환합니다.

Task.Delay(1000)

  • 비동기 작업을 시뮬레이션하기 위해 1초 동안 대기합니다.
  • 작업의 실행은 일시 중단되지만, 메인 스레드는 블로킹되지 않아 다른 작업을 계속 실행할 수 있습니다.

await 키워드

  • PerformDoubleTask의 완료를 비동기적으로 기다립니다.
  • 대기가 끝난 후 반환값(두 배로 계산된 값)을 처리합니다.

 

실행 흐름

  1. Start 호출: 스크립트가 활성화되면 Start 메서드가 호출됩니다.
  2. PerformDoubleTask 호출: 5를 사용하여 비동기 작업을 실행합니다.
  3. 1초 대기: Task.Delay(1000)로 인해 1초 동안 대기합니다.
  4. 결과 반환: 1초 후, 입력값 5가 두 배로 계산되어 10을 반환합니다.
  5. 결과 출력: 결과를 콘솔에 출력합니다. 
    "작업 시작"
    "결과: 10"

 

Task의 응용

 

Task 병렬 처리

Task.WhenAll은 여러 비동기 작업이 모두 완료된 후에야 다음 작업을 수행해야 할 때 유용합니다.

 

예제: 유니티에서 데이터 로드

 
async Task InitializeGame()
{
    Task loadPlayerData = LoadPlayerDataAsync();
    Task loadEnvironmentData = LoadEnvironmentDataAsync();
    Task loadSettings = LoadSettingsAsync();

    await Task.WhenAll(loadPlayerData, loadEnvironmentData, loadSettings);

    Debug.Log("모든 데이터 로드 완료");
}

async Task LoadPlayerDataAsync()
{
    await Task.Delay(1000); // 예: 서버에서 플레이어 데이터를 가져옴
    Debug.Log("플레이어 데이터 로드 완료");
}

async Task LoadEnvironmentDataAsync()
{
    await Task.Delay(1500); // 예: 맵 데이터를 가져옴
    Debug.Log("환경 데이터 로드 완료");
}

async Task LoadSettingsAsync()
{
    await Task.Delay(800); // 예: 게임 설정 데이터를 가져옴
    Debug.Log("설정 데이터 로드 완료");
}

 

병렬 작업 후 결과 취합

Task.WhenAll은 모든 작업의 결과를 배열 형태로 반환합니다. 이를 통해 여러 작업의 결과를 하나로 취합할 수 있습니다.

 

예제: 서버에서 데이터 가져오기

async Task FetchGameData()
{
    Task<int> playerLevelTask = GetPlayerLevelAsync();
    Task<string> mapNameTask = GetMapNameAsync();

    var results = await Task.WhenAll(playerLevelTask, mapNameTask);

    int playerLevel = results[0]; // 첫 번째 Task 결과
    string mapName = results[1]; // 두 번째 Task 결과

    Debug.Log($"플레이어 레벨: {playerLevel}, 현재 맵: {mapName}");
}

async Task<int> GetPlayerLevelAsync()
{
    await Task.Delay(1000); // 데이터베이스 호출 시뮬레이션
    return 25; // 플레이어 레벨
}

async Task<string> GetMapNameAsync()
{
    await Task.Delay(1200); // 데이터베이스 호출 시뮬레이션
    return "Dragon Valley"; // 맵 이름
}

 

에러 처리

Task.WhenAll은 여러 작업 중 하나라도 예외가 발생하면 그 예외를 throw합니다. 하지만 모든 작업이 완료된 후에 예외를 확인할 수 있습니다.

 

예제: 오류를 포함한 비동기 작업

async Task PerformMultipleTasksWithErrorHandling()
{
    try
    {
        Task task1 = SimulateTaskWithError("Task1");
        Task task2 = SimulateTask("Task2");

        await Task.WhenAll(task1, task2);
    }
    catch (Exception ex)
    {
        Debug.LogError($"작업 중 오류 발생: {ex.Message}");
    }
}

async Task SimulateTaskWithError(string name)
{
    await Task.Delay(500);
    throw new Exception($"{name} 실패");
}

async Task SimulateTask(string name)
{
    await Task.Delay(700);
    Debug.Log($"{name} 성공");
}

 

 

Task.WhenAny 예제

async Task WaitForAnyTask()
{
    Task task1 = SimulateTask("Task1", 1500);
    Task task2 = SimulateTask("Task2", 1000);

    Task firstCompleted = await Task.WhenAny(task1, task2);
    Debug.Log($"{firstCompleted.Id}가 먼저 완료됨");
}

async Task SimulateTask(string name, int delay)
{
    await Task.Delay(delay);
    Debug.Log($"{name} 완료");
}

 

Task.WhenAll과 Task.WhenAny의 차이

  • Task.WhenAll: 모든 작업이 완료될 때까지 기다림. 결과 배열을 반환하거나 예외를 throw합니다.
  • Task.WhenAny: 첫 번째로 완료된 작업을 기다림. 어떤 작업이 완료되었는지 반환합니다.

 

Unity에서 Task를 사용해야 할 상황

Unity에서 Task는 주로 Unity 외부의 비동기 작업이나 성능 최적화를 위한 병렬 처리에 사용됩니다.

 

Unity 게임 개발의 Task 사용 예시

HTTP 요청 처리 - UnityWebRequest보다 더 복잡한 요청이 필요한 경우, Task를 통해 처리.

using System.Net.Http;
using System.Threading.Tasks;
using UnityEngine;

public class HttpExample : MonoBehaviour
{
    private async void Start()
    {
        string data = await FetchData("https://api.example.com/data");
        Debug.Log($"받은 데이터: {data}");
    }

    private async Task<string> FetchData(string url)
    {
        using HttpClient client = new HttpClient();
        return await client.GetStringAsync(url);
    }
}

 

 

파일 입출력 - 게임 데이터를 비동기로 저장하고 로드하여 메인 스레드의 성능 유지.

using System.IO;
using System.Threading.Tasks;
using UnityEngine;

public class FileExample : MonoBehaviour
{
    private async void Start()
    {
        string filePath = Application.persistentDataPath + "/data.txt";
        await WriteToFile(filePath, "Hello, Task!");
        string content = await ReadFromFile(filePath);
        Debug.Log($"파일 내용: {content}");
    }

    private async Task WriteToFile(string path, string content)
    {
        await File.WriteAllTextAsync(path, content);
    }

    private async Task<string> ReadFromFile(string path)
    {
        return await File.ReadAllTextAsync(path);
    }
}​

 

728x90