기술 자료

Unity Engine

Unity Engine

Awaitable 코드 예시 레퍼런스

Solve common asynchronous programming problems with a reference of Awaitable code examples.
읽는 시간 3분최근 업데이트: 한 달 전

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

비동기적 테스트

Unity의 테스트 프레임워크는
Awaitable
을 유효한 테스트 반환 유형으로 인식하지 않습니다. 그러나 다음 예시는
IEnumerator
의
Awaitable
구현을 사용하여 비동기 테스트를 작성하는 방법을 보여줍니다.
[UnityTest]public IEnumerator SomeAsyncTest(){ async Awaitable TestImplementation(){ // test something with async / await support here }; return TestImplementation();}

프레임 코루틴

Awaitable
클래스에서 프레임 관련 비동기 메서드를 사용하여 반복자 기반 코루틴을 대체하는 비동기 Unity 코루틴을 생성할 수 있습니다.
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(){ ...}

조건부 대기

반복자 기반 코루틴에서 WaitUntil은 델리게이트가
true
를 평가할 때까지 코루틴 실행을 일시 중지합니다. 취소 토큰을 사용하여 조건이 변경될 때까지 기다리게 함으로써
Awaitable
반환 비동기 메서드와 동등한 동작을 만들 수 있습니다.
public static async AwaitableUntil(Func<bool> condition, CancellationTokenSource cancellationToken){ while(!condition()){ cancellationToken.ThrowIfCancellationRequested(); await Awaitable.NextFrameAsync(); }}
이후에 다음과 같이 취소 토큰을 전달할 수 있습니다.
cancellationTokenSource = new CancellationTokenSource();currentTask = AwaitableUntil(myCondition, cancellationTokenSource.Token);

비동기식으로 리소스 로드

메인 스레드를 차단하지 않도록 비동기식 리소스 로드 작업을
await
할 수 있습니다.
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;}

합성

동일한 방법으로 여러 개의 서로 다른
await
호환 유형을
await
할 수 있습니다.
public async Awaitable Start(){ await CallSomeThirdPartyAPIReturningDotnetTask(); await Awaitable.NextFrameAsync(); await SceneManager.LoadSceneAsync("my-scene"); await SomeUserCodeReturningAwaitable(); ...}

.NET Task에서 Awaitable 래핑

.NET
Task
래핑하여
Awaitable
의 몇 가지 제한 사항을 우회할 수 있습니다. 이렇게 하면 할당 비용이 발생하지만
Task
API의
WhenAll
및
WhenAny
와 같은 메서드에 액세스할 수 있게 됩니다. 이를 위해서는 다음과 같이 커스텀
AsTask
확장 메서드를 자체적으로 작성할 수 있습니다.
// Implement custom AsTask extension methods to wrap Awaitable in Taskpublic 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; } }

결과를 여러 번 기다리기

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

안전하지 않은 버전

다음 코드는 안전하지 않으며 예외와 멈춤 현상을 발생시킵니다.
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; }

안전한 버전

이는 할당 비용을 감수하면서 Awaitable을 Task에 래핑할 수 있는 시나리오에 해당합니다. 이를 통해
Task
를 여러 번 안전하게 기다릴 수 있습니다.
// Implement custom AsTask extension methods to wrap Awaitable in Taskpublic 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; }

추가 리소스