# Awaitable 코드 예시 레퍼런스

> Solve common asynchronous programming problems with a reference of Awaitable code examples.

이 레퍼런스의 예시들은 비동기 코드를 작성할 때 발생하는 일반적인 시나리오에서 사용할 수 있는 `Awaitable` 솔루션을 보여줍니다.

## 비동기적 테스트##asynchronous-tests

Unity의 [테스트 프레임워크](/engine/6000.0/manual/scripting/environment-and-tools/testing-editortestsrunner.md)는 `Awaitable`을 유효한 테스트 반환 유형으로 인식하지 않습니다. 그러나 다음 예시는 `IEnumerator`의 `Awaitable` 구현을 사용하여 비동기 테스트를 작성하는 방법을 보여줍니다.

```lang-csharp
[UnityTest]
public IEnumerator SomeAsyncTest(){
    async Awaitable TestImplementation(){
        // test something with async / await support here
    };
    return TestImplementation();
}
```

## 프레임 코루틴##frame-coroutines

`Awaitable` 클래스에서 프레임 관련 비동기 메서드를 사용하여 반복자 기반 코루틴을 대체하는 비동기 Unity 코루틴을 생성할 수 있습니다.

```lang-csharp
async Awaitable SampleSchedulingJobsForNextFrame()
{
    // Wait until end of frame to avoid competing over resources with other Unity subsystems
    await Awaitable.EndOfFrameAsync(); 
    var jobHandle = ScheduleSomethingWithJobSystem();
    // Let the job execute while the next frame starts
    await Awaitable.NextFrameAsync();
    jobHandle.Complete();
    // Use results of computation
}

JobHandle ScheduleSomethingWithJobSystem()
{
    ...
}
```

### 조건부 대기##conditional-wait

반복자 기반 코루틴에서 [WaitUntil](/engine/6000.0/script-reference/unity-engine/wait-until.md)은 델리게이트가 `true`를 평가할 때까지 코루틴 실행을 일시 중지합니다. 취소 토큰을 사용하여 조건이 변경될 때까지 기다리게 함으로써 `Awaitable` 반환 비동기 메서드와 동등한 동작을 만들 수 있습니다.

```lang-csharp
public static async AwaitableUntil(Func<bool> condition, CancellationTokenSource cancellationToken)
{
   while(!condition()){
     cancellationToken.ThrowIfCancellationRequested();
     await Awaitable.NextFrameAsync();
  }
}
```

이후에 다음과 같이 취소 토큰을 전달할 수 있습니다.

```lang-csharp
cancellationTokenSource = new CancellationTokenSource();
currentTask = AwaitableUntil(myCondition, cancellationTokenSource.Token);
```

## 비동기식으로 리소스 로드##loading-resources-asynchronously

메인 스레드를 차단하지 않도록 비동기식 리소스 로드 작업을 `await`할 수 있습니다.

```lang-csharp
public async Awaitable Start()
{
    // Load texture resource asynchronously
    var operation = Resources.LoadAsync("my-texture");
    // Return control to the main thread while the resource loads
    await operation;
    var texture = operation.asset as Texture2D;
}
```

## 합성##composition

동일한 방법으로 여러 개의 서로 다른 `await` 호환 유형을 `await`할 수 있습니다.

```lang-csharp
public async Awaitable Start()
{
    await CallSomeThirdPartyAPIReturningDotnetTask();
    await Awaitable.NextFrameAsync();
    await SceneManager.LoadSceneAsync("my-scene");
    await SomeUserCodeReturningAwaitable();
    ...
}
```

## .NET Task에서 Awaitable 래핑##wrapping-awaitable-in-.net-task

.NET `Task` 래핑하여 `Awaitable`의 몇 가지 제한 사항을 우회할 수 있습니다. 이렇게 하면 할당 비용이 발생하지만 `Task` API의 `WhenAll` 및 `WhenAny`와 같은 메서드에 액세스할 수 있게 됩니다. 이를 위해서는 다음과 같이 커스텀 `AsTask` 확장 메서드를 자체적으로 작성할 수 있습니다.

```lang-csharp
// Implement custom AsTask extension methods to wrap Awaitable in Task
public static class AwaitableExtensions
    {
        public static async Task AsTask(this Awaitable a)
        {
            await a;
        }

        public static async Task<T> AsTask<T>(this Awaitable<T> a)
        {
            return await a;
        }
    }
```

## 결과를 여러 번 기다리기##await-a-result-multiple-times

`Awaitable`과 `Task`의 주요 차이점은 할당을 줄이기 위해 `Awaitable` 객체를 풀링하는 것입니다. 결과를 여러 번 완료하는 `Awaitable` 반환 메서드를 안전하게 `await`할 수는 없습니다. 이는 원본 `Awaitable` 오브젝트는 반환된 이후에 풀로 돌아가기 때문입니다.

### 안전하지 않은 버전##unsafe-version

다음 코드는 **안전하지 않으며** 예외와 멈춤 현상을 발생시킵니다.

```lang-csharp
async Awaitable Bar(){
  var taskWithResult = SomeAwaitableReturningFunction();
  var awaitOnce = await taskWithResult;
  // Do something
  // The following will cause errors because at this point taskWithResult has already been pooled back
  var awaitTwice = await taskWithResult;
 }
```

### 안전한 버전##safe-version

이는 할당 비용을 감수하면서 [Awaitable을 Task에 래핑할](#awaitable-as-task) 수 있는 시나리오에 해당합니다. 이를 통해 `Task`를 여러 번 안전하게 기다릴 수 있습니다.

```lang-csharp
// Implement custom AsTask extension methods to wrap Awaitable in Task
public static class AwaitableExtensions
    {
        public static async Task AsTask(this Awaitable a)
        {
            await a;
        }

        public static async Task<T> AsTask<T>(this Awaitable<T> a)
        {
            return await a;
        }
    }

async Awaitable Bar(){
  var taskWithResult = SomeAwaitableReturningFunction();
  // Wrap the returned Awaitable in a Task
  var taskWithResultAsTask = taskWithResult.AsTask();
  // The task can now be safely awaited multiple times, at the cost of allocating
  var awaitOnce = await taskWithResultAsTask;
  // Do something
  var awaitTwice = await taskWithResultAsTask;
 }
```

## 추가 리소스##additional-resources

* [Unity Awaitable과 .NET Task 비교](/engine/6000.0/manual/scripting/optimization/async-await-support/async-awaitable-introduction.md)
* [비동기 작업 지속 및 완료](/engine/6000.0/manual/scripting/optimization/async-await-support/async-awaitable-continuations.md)
* [Awaitable API 레퍼런스](/engine/6000.0/script-reference/unity-engine/awaitable.md)
