Unity를위한 효율적인 할당 무료 비스듬한/대기업 통합을 제공합니다.
UniTask<T>
및 맞춤형 비동기 제도 구매자UniTask.Yield
, UniTask.Delay
, UniTask.DelayFrame
등) 기술적 인 자세한 내용은 블로그 게시물을 참조하십시오 : Unitask V2 - 비동기 LINQ와 함께 UNITY의 제로 할당 비동기/대기
고급 팁은 블로그 게시물을 참조하십시오 : 비동기 데코레이터 패턴을 통해 UnityWebRequest 확장 - 유니 토스의 고급 기술
Unitask/Releases에서 사용할 수있는 GIT 참조 또는 자산 패키지 ( UniTask.*.*.*.unitypackage
)와 함께 UPM 패키지를 통해 설치하십시오.
// extension awaiter/methods can be used by this namespace
using Cysharp . Threading . Tasks ;
// You can return type as struct UniTask<T>(or UniTask), it is unity specialized lightweight alternative of Task<T>
// zero allocation and fast excution for zero overhead async/await integrate with Unity
async UniTask < string > DemoAsync ( )
{
// You can await Unity's AsyncObject
var asset = await Resources . LoadAsync < TextAsset > ( " foo " ) ;
var txt = ( await UnityWebRequest . Get ( " https://... " ) . SendWebRequest ( ) ) . downloadHandler . text ;
await SceneManager . LoadSceneAsync ( " scene2 " ) ;
// .WithCancellation enables Cancel, GetCancellationTokenOnDestroy synchornizes with lifetime of GameObject
// after Unity 2022.2, you can use `destroyCancellationToken` in MonoBehaviour
var asset2 = await Resources . LoadAsync < TextAsset > ( " bar " ) . WithCancellation ( this . GetCancellationTokenOnDestroy ( ) ) ;
// .ToUniTask accepts progress callback(and all options), Progress.Create is a lightweight alternative of IProgress<T>
var asset3 = await Resources . LoadAsync < TextAsset > ( " baz " ) . ToUniTask ( Progress . Create < float > ( x => Debug . Log ( x ) ) ) ;
// await frame-based operation like a coroutine
await UniTask . DelayFrame ( 100 ) ;
// replacement of yield return new WaitForSeconds/WaitForSecondsRealtime
await UniTask . Delay ( TimeSpan . FromSeconds ( 10 ) , ignoreTimeScale : false ) ;
// yield any playerloop timing(PreUpdate, Update, LateUpdate, etc...)
await UniTask . Yield ( PlayerLoopTiming . PreLateUpdate ) ;
// replacement of yield return null
await UniTask . Yield ( ) ;
await UniTask . NextFrame ( ) ;
// replacement of WaitForEndOfFrame
# if UNITY_2023_1_OR_NEWER
await UniTask . WaitForEndOfFrame ( ) ;
# else
// requires MonoBehaviour(CoroutineRunner))
await UniTask . WaitForEndOfFrame ( this ) ; // this is MonoBehaviour
#endif
// replacement of yield return new WaitForFixedUpdate(same as UniTask.Yield(PlayerLoopTiming.FixedUpdate))
await UniTask . WaitForFixedUpdate ( ) ;
// replacement of yield return WaitUntil
await UniTask . WaitUntil ( ( ) => isActive == false ) ;
// special helper of WaitUntil
await UniTask . WaitUntilValueChanged ( this , x => x . isActive ) ;
// You can await IEnumerator coroutines
await FooCoroutineEnumerator ( ) ;
// You can await a standard task
await Task . Run ( ( ) => 100 ) ;
// Multithreading, run on ThreadPool under this code
await UniTask . SwitchToThreadPool ( ) ;
/* work on ThreadPool */
// return to MainThread(same as `ObserveOnMainThread` in UniRx)
await UniTask . SwitchToMainThread ( ) ;
// get async webrequest
async UniTask < string > GetTextAsync ( UnityWebRequest req )
{
var op = await req . SendWebRequest ( ) ;
return op . downloadHandler . text ;
}
var task1 = GetTextAsync ( UnityWebRequest . Get ( " http://google.com " ) ) ;
var task2 = GetTextAsync ( UnityWebRequest . Get ( " http://bing.com " ) ) ;
var task3 = GetTextAsync ( UnityWebRequest . Get ( " http://yahoo.com " ) ) ;
// concurrent async-wait and get results easily by tuple syntax
var ( google , bing , yahoo ) = await UniTask . WhenAll ( task1 , task2 , task3 ) ;
// shorthand of WhenAll, tuple can await directly
var ( google2 , bing2 , yahoo2 ) = await ( task1 , task2 , task3 ) ;
// return async-value.(or you can use `UniTask`(no result), `UniTaskVoid`(fire and forget)).
return ( asset as TextAsset ) ? . text ?? throw new InvalidOperationException ( " Asset not found " ) ;
}
Unitask 기능은 C# 7.0 (작업 형 맞춤형 Async 메소드 빌더 기능)에 의존하므로 필요한 Unity 버전은 Unity 2018.3
이후에 지원되는 공식 최저 버전은 Unity 2018.4.13f1
입니다.
Unitask (사용자 정의 작업과 같은 개체)가 필요한 이유는 무엇입니까? 작업이 너무 무겁고 유니티 스레딩 (단일 스레드)과 일치하지 않기 때문입니다. UNITY의 비동기 객체는 Unity의 엔진 계층에 의해 자동으로 발산되기 때문에 UnitASK는 스레드 및 SynchronizationContext/ExecutionContext를 사용하지 않습니다. 더 빠르고 낮은 할당을 달성하며 Unity와 완전히 통합됩니다.
using Cysharp.Threading.Tasks;
때 AsyncOperation
, ResourceRequest
, AssetBundleRequest
, AssetBundleCreateRequest
, UnityWebRequestAsyncOperation
, AsyncGPUReadbackRequest
, IEnumerator
및 기타를 기다릴 수 있습니다. .
유닛 ask는 세 가지 확장 방법 패턴을 제공합니다.
* await asyncOperation ;
* . WithCancellation ( CancellationToken ) ;
* . ToUniTask ( IProgress , PlayerLoopTiming , CancellationToken ) ;
WithCancellation
은 ToUniTask
의 간단한 버전입니다 UniTask
취소에 대한 자세한 내용은 취소 및 예외 처리 섹션을 참조하십시오.
참고 : AWAIT은 PlayerLoop의 기본 타이밍에서 직접 반환되지만 지정된 PlayerLooptiming에서 세포화 및 Tounitask가 반환됩니다. 타이밍에 대한 자세한 내용은 PlayerLoop 섹션을 참조하십시오.
참고 : Assetbundlerequest에는
asset
과allAssets
있으며 기본 자산이 반품asset
기다립니다.allAssets
얻으려면AwaitForAllAssets()
메소드를 사용할 수 있습니다.
UniTask
의 유형은 UniTask.WhenAll
, UniTask.WhenAny
, UniTask.WhenEach
와 같은 유틸리티를 사용할 수 있습니다. 이들은 Task.WhenAll
Task.WhenAny
같습니다. 값 튜플을 반환하여 각 결과를 해체하고 여러 유형을 통과 할 수 있습니다.
public async UniTaskVoid LoadManyAsync ( )
{
// parallel load.
var ( a , b , c ) = await UniTask . WhenAll (
LoadAsSprite ( " foo " ) ,
LoadAsSprite ( " bar " ) ,
LoadAsSprite ( " baz " ) ) ;
}
async UniTask < Sprite > LoadAsSprite ( string path )
{
var resource = await Resources . LoadAsync < Sprite > ( path ) ;
return ( resource as Sprite ) ;
}
콜백을 Unitask로 변환하려면 TaskCompletionSource<T>
의 경량판 인 UniTaskCompletionSource<T>
사용할 수 있습니다.
public UniTask < int > WrapByUniTaskCompletionSource ( )
{
var utcs = new UniTaskCompletionSource < int > ( ) ;
// when complete, call utcs.TrySetResult();
// when failed, call utcs.TrySetException();
// when cancel, call utcs.TrySetCanceled();
return utcs . Task ; //return UniTask<int>
}
작업 -> Unitask : AsUniTask
, UniTask
> UniTask<AsyncUnit>
: AsAsyncUnitUniTask
, UniTask<T>
-> UniTask
: AsUniTask
변환 할 수 있습니다. UniTask<T>
-> UniTask
의 전환 비용은 무료입니다.
Async를 Coroutine으로 변환하려면 .ToCoroutine()
을 사용할 수 있습니다. Coroutine 시스템 만 사용하는 경우 유용합니다.
유닛 ask는 두 번 기다릴 수 없습니다. 이는 .NET 표준 2.1에 도입 된 Valuetask/IvaluetaskSource와 유사한 제약입니다.
Valuetask 인스턴스에서는 다음 작업을 수행해서는 안됩니다.
- 인스턴스를 여러 번 기다리고 있습니다.
- Astask를 여러 번 호출합니다.
- 작업이 아직 완료되지 않았을 때 .result 또는 .getawaiter (). getResult () 사용 또는 여러 번 사용합니다.
- 이러한 기술 중 하나 이상을 사용하여 인스턴스를 소비합니다.
위의 일을 수행하면 결과가 정의되지 않습니다.
var task = UniTask . DelayFrame ( 10 ) ;
await task ;
await task ; // NG, throws Exception
클래스 필드에 보관하면 여러 번 통화를 지원하는 UniTask.Lazy
사용할 수 있습니다. .Preserve()
여러 통화 (내부 캐시 된 결과)를 허용합니다. 기능 범위에 여러 통화가있을 때 유용합니다.
또한 UniTaskCompletionSource
여러 번 기다릴 수 있으며 많은 발신자로부터 기다릴 수 있습니다.
일부 Unitask Factory Methods에는 CancellationToken cancellationToken = default
매개 변수가 있습니다. 또한 유니티에 대한 일부 비동기 작업에는 WithCancellation(CancellationToken)
및 ToUniTask(..., CancellationToken cancellation = default)
확장 메소드가 있습니다.
Standard CancellationTokenSource
를 통해 CancellationToken
매개 변수로 전달할 수 있습니다.
var cts = new CancellationTokenSource ( ) ;
cancelButton . onClick . AddListener ( ( ) =>
{
cts . Cancel ( ) ;
} ) ;
await UnityWebRequest . Get ( " http://google.co.jp " ) . SendWebRequest ( ) . WithCancellation ( cts . Token ) ;
await UniTask . DelayFrame ( 1000 , cancellationToken : cts . Token ) ;
CancellationToken은 CancellationTokenSource
또는 Monobehaviour의 확장 방법 GetCancellationTokenOnDestroy
에 의해 만들 수 있습니다.
// this CancellationToken lifecycle is same as GameObject.
await UniTask . DelayFrame ( 1000 , cancellationToken : this . GetCancellationTokenOnDestroy ( ) ) ;
전파 된 취소의 경우, 모든 비동기 메소드는 마지막 인수에서 CancellationToken cancellationToken
받아들이고 루트에서 끝으로 CancellationToken
통과하는 것이 좋습니다.
await FooAsync ( this . GetCancellationTokenOnDestroy ( ) ) ;
// ---
async UniTask FooAsync ( CancellationToken cancellationToken )
{
await BarAsync ( cancellationToken ) ;
}
async UniTask BarAsync ( CancellationToken cancellationToken )
{
await UniTask . Delay ( TimeSpan . FromSeconds ( 3 ) , cancellationToken ) ;
}
CancellationToken
비동기의 수명주기를 의미합니다. Default CancellationTokenonDestroy 대신 자신의 수명주기를 보관할 수 있습니다.
public class MyBehaviour : MonoBehaviour
{
CancellationTokenSource disableCancellation = new CancellationTokenSource ( ) ;
CancellationTokenSource destroyCancellation = new CancellationTokenSource ( ) ;
private void OnEnable ( )
{
if ( disableCancellation != null )
{
disableCancellation . Dispose ( ) ;
}
disableCancellation = new CancellationTokenSource ( ) ;
}
private void OnDisable ( )
{
disableCancellation . Cancel ( ) ;
}
private void OnDestroy ( )
{
destroyCancellation . Cancel ( ) ;
destroyCancellation . Dispose ( ) ;
}
}
Unity 2022.2 이후, Unity는 monobehaviour.destroycancellationtoken 및 application.exitcancellationToken에서 CancellationToken을 추가합니다.
취소가 감지되면 모든 방법은 OperationCanceledException
던지고 상류로 전파됩니다. 예외 ( OperationCanceledException
에 제한되지 않음)가 Async 방법으로 처리되지 않으면 최종적으로 UniTaskScheduler.UnobservedTaskException
으로 전파됩니다. 수신되지 않은 예외의 기본 동작은 로그를 예외로 작성하는 것입니다. 로그 레벨은 UniTaskScheduler.UnobservedExceptionWriteLogType
사용하여 변경할 수 있습니다. 사용자 정의 동작을 사용하려면 UniTaskScheduler.UnobservedTaskException.
또한 OperationCanceledException
은 특별한 예외이며, 이는 UnobservedTaskException
경우 조용히 무시됩니다.
비동기 유니ask 방법으로 동작을 취소하려면 OperationCanceledException
수동으로 던지십시오.
public async UniTask < int > FooAsync ( )
{
await UniTask . Yield ( ) ;
throw new OperationCanceledException ( ) ;
}
예외를 처리하지만 무시하려면 (글로벌 취소 처리로 전파) 예외 필터를 사용하십시오.
public async UniTask < int > BarAsync ( )
{
try
{
var x = await FooAsync ( ) ;
return x * 2 ;
}
catch ( Exception ex ) when ( ! ( ex is OperationCanceledException ) ) // when (ex is not OperationCanceledException) at C# 9.0
{
return - 1 ;
}
}
던지기/캐치 OperationCanceledException
약간 무겁기 때문에 성능이 우려되는 경우 UniTask.SuppressCancellationThrow
사용하여 OperationCancelException 던지기를 피하십시오. 던지는 대신 반환 (bool IsCanceled, T Result)
을 반환합니다.
var ( isCanceled , _ ) = await UniTask . DelayFrame ( 10 , cancellationToken : cts . Token ) . SuppressCancellationThrow ( ) ;
if ( isCanceled )
{
// ...
}
참고 : 가장 많은 소스 방법으로 직접 호출하는 경우 발생 만 억제합니다. 그렇지 않으면 반환 값이 변환되지만 전체 파이프 라인은 던지기를 억제하지 않습니다.
UniTask.Yield
및 UniTask.Delay
등과 같은 Unity의 플레이어 루프를 사용하는 일부 기능은 플레이어 루프에서 취소 상태를 결정합니다. 즉, CancellationToken
해산되면 즉시 취소되지 않음을 의미합니다.
이 동작을 바꾸려면 취소가 즉각적이 되려면 cancelImmediately
플래그를 인수로 설정하십시오.
await UniTask . Yield ( cancellationToken , cancelImmediately : true ) ;
참고 : cancelImmediately
하고 즉시 취소를 감지하는 것은 기본 동작보다 비용이 많이 듭니다. CancellationToken.Register
사용하기 때문입니다. 플레이어 루프에서 취소를 확인하는 것보다 무겁습니다.
시간 초과는 취소의 변형입니다. CancellationTokenSouce.CancelAfterSlim(TimeSpan)
으로 시간 초과를 설정하고 vancellationToken을 비동기 메소드로 전달할 수 있습니다.
var cts = new CancellationTokenSource ( ) ;
cts . CancelAfterSlim ( TimeSpan . FromSeconds ( 5 ) ) ; // 5sec timeout.
try
{
await UnityWebRequest . Get ( " http://foo " ) . SendWebRequest ( ) . WithCancellation ( cts . Token ) ;
}
catch ( OperationCanceledException ex )
{
if ( ex . CancellationToken == cts . Token )
{
UnityEngine . Debug . Log ( " Timeout " ) ;
}
}
CancellationTokenSouce.CancelAfter
는 표준 API입니다. 그러나 유니티에서는 스레딩 타이머에 따라 사용되므로 사용해서는 안됩니다.CancelAfterSlim
Unitask의 확장 방법이며 대신 PlayerLoop을 사용합니다.
다른 취소 소스와 함께 시간 초과를 사용하려면 CancellationTokenSource.CreateLinkedTokenSource
사용하십시오.
var cancelToken = new CancellationTokenSource ( ) ;
cancelButton . onClick . AddListener ( ( ) =>
{
cancelToken . Cancel ( ) ; // cancel from button click.
} ) ;
var timeoutToken = new CancellationTokenSource ( ) ;
timeoutToken . CancelAfterSlim ( TimeSpan . FromSeconds ( 5 ) ) ; // 5sec timeout.
try
{
// combine token
var linkedTokenSource = CancellationTokenSource . CreateLinkedTokenSource ( cancelToken . Token , timeoutToken . Token ) ;
await UnityWebRequest . Get ( " http://foo " ) . SendWebRequest ( ) . WithCancellation ( linkedTokenSource . Token ) ;
}
catch ( OperationCanceledException ex )
{
if ( timeoutToken . IsCancellationRequested )
{
UnityEngine . Debug . Log ( " Timeout. " ) ;
}
else if ( cancelToken . IsCancellationRequested )
{
UnityEngine . Debug . Log ( " Cancel clicked. " ) ;
}
}
통화 Async Method 당 시간 초과에 대한 CancellationTokenSource의 할당 감소를 위해 최적화하십시오. Unitask의 TimeoutController
사용할 수 있습니다.
TimeoutController timeoutController = new TimeoutController ( ) ; // setup to field for reuse.
async UniTask FooAsync ( )
{
try
{
// you can pass timeoutController.Timeout(TimeSpan) to cancellationToken.
await UnityWebRequest . Get ( " http://foo " ) . SendWebRequest ( )
. WithCancellation ( timeoutController . Timeout ( TimeSpan . FromSeconds ( 5 ) ) ) ;
timeoutController . Reset ( ) ; // call Reset(Stop timeout timer and ready for reuse) when succeed.
}
catch ( OperationCanceledException ex )
{
if ( timeoutController . IsTimeout ( ) )
{
UnityEngine . Debug . Log ( " timeout " ) ;
}
}
}
다른 취소 소스와 함께 시간 초과를 사용하려면 new TimeoutController(CancellationToken)
사용하십시오.
TimeoutController timeoutController ;
CancellationTokenSource clickCancelSource ;
void Start ( )
{
this . clickCancelSource = new CancellationTokenSource ( ) ;
this . timeoutController = new TimeoutController ( clickCancelSource ) ;
}
참고 : Unitask에는 .Timeout
, .TimeoutWithoutException
메소드가 있지만 가능하면 사용하지 않으시면 CancellationToken
통과하십시오. . .Timeout
작업의 외부 작업은 타임 아웃 작업을 중지 할 수 없기 때문입니다. .Timeout
시간 초과시 결과를 무시한다는 것을 의미합니다. CancellationToken
메소드로 전달하면 작업 내부에서 작동하므로 실행 작업을 중지 할 수 있습니다.
유니티에 대한 일부 비동기 작업에는 ToUniTask(IProgress<float> progress = null, ...)
확장 메소드가 있습니다.
var progress = Progress . Create < float > ( x => Debug . Log ( x ) ) ;
var request = await UnityWebRequest . Get ( " http://google.co.jp " )
. SendWebRequest ( )
. ToUniTask ( progress : progress ) ;
표준 new System.Progress<T>
사용해서는 안됩니다. Cysharp.Threading.Tasks.Progress
대신 사용하십시오. 이 진보 공장에는 두 가지 Create
CreateOnlyValueChanged
있습니다. CreateOnlyValueChanged
진행 값이 변경된 경우에만 호출됩니다.
람다 할당이 없으므로 발신자에게 iprogress 인터페이스를 구현하는 것이 좋습니다.
public class Foo : MonoBehaviour , IProgress < float >
{
public void Report ( float value )
{
UnityEngine . Debug . Log ( value ) ;
}
public async UniTaskVoid WebRequest ( )
{
var request = await UnityWebRequest . Get ( " http://google.co.jp " )
. SendWebRequest ( )
. ToUniTask ( progress : this ) ; // pass this
}
}
Unitask는 사용자 정의 PlayerLoop에서 실행됩니다. Unitask의 PlayerLoop 기반 방법 ( Delay
, DelayFrame
, asyncOperation.ToUniTask
등) 은이 PlayerLoopTiming
수락합니다.
public enum PlayerLoopTiming
{
Initialization = 0 ,
LastInitialization = 1 ,
EarlyUpdate = 2 ,
LastEarlyUpdate = 3 ,
FixedUpdate = 4 ,
LastFixedUpdate = 5 ,
PreUpdate = 6 ,
LastPreUpdate = 7 ,
Update = 8 ,
LastUpdate = 9 ,
PreLateUpdate = 10 ,
LastPreLateUpdate = 11 ,
PostLateUpdate = 12 ,
LastPostLateUpdate = 13
# if UNITY_2020_2_OR_NEWER
TimeUpdate = 14 ,
LastTimeUpdate = 15 ,
#endif
}
실행시기를 나타냅니다. PlayerLoopList.md를 Unity의 Default PlayerLoop로 확인하고 UnitASK의 사용자 정의 루프를 주입 할 수 있습니다.
PlayerLoopTiming.Update
는 코 루틴에서 yield return null
과 유사하지만 업데이트 전에 호출됩니다 (업데이트 및 UGUI 이벤트 (Button.OnClick 등)는 ScriptRunBehaviourUpdate
에서 호출되며 ScriptRunDelayedDynamicFrameRate
에서 수율 리턴 NULL이 호출됩니다. PlayerLoopTiming.FixedUpdate
WaitForFixedUpdate
와 유사합니다.
PlayerLoopTiming.LastPostLateUpdate
는 Coroutine의yield return new WaitForEndOfFrame()
와 같지 않습니다. Coroutine의 Waitforendofframe은 PlayerLoop가 완료된 후에 실행되는 것 같습니다. Coroutine의 프레임 끝 (Texture2D.ReadPixels
,ScreenCapture.CaptureScreenshotAsTexture
,CommandBuffer
등)이 필요한 일부 방법은 Async/Await로 교체 할 때 올바르게 작동하지 않습니다. 이 경우 Monobehaviour (Coroutine Runnner)를UniTask.WaitForEndOfFrame
으로 통과하십시오. 예를 들어,await UniTask.WaitForEndOfFrame(this);
Lightweight 할당 무료 대안yield return new WaitForEndOfFrame()
.참고 : Unity 2023.1 또는 최신 인
await UniTask.WaitForEndOfFrame();
더 이상 Monobehaviour가 필요하지 않습니다.UnityEngine.Awaitable.EndOfFrameAsync
사용합니다.
yield return null
및 UniTask.Yield
는 비슷하지만 다릅니다. yield return null
항상 다음 프레임을 반환하지만 UniTask.Yield
다음으로 전화합니다. 즉, PreUpdate
에서 UniTask.Yield(PlayerLoopTiming.Update)
호출하면 같은 프레임을 반환합니다. UniTask.NextFrame()
다음 프레임을 반환하는 것을 보증합니다. yield return null
과 정확히 동일하게 행동 할 수 있습니다.
Unitask.yield (CancellationToken이없는)는 특수 유형이며,
YieldAwaitable
반환하고 수율 러너에서 실행됩니다. 가장 가볍고 빠릅니다.
AsyncOperation
기본 타이밍에서 반환됩니다. Start
EarlyUpdate.UpdatePreloading
들어, EarlyUpdate.ScriptRunDelayedStartupFrame
SceneManager.LoadSceneAsync
또한 await UnityWebRequest
EarlyUpdate.ExecuteMainThreadJobs
에서 반환됩니다.
Unitask에서 기다리는 것은 기본 타이밍을 직접 사용하는 반면, WithCancellation
및 ToUniTask
지정된 타이밍을 사용합니다. 이것은 일반적으로 특정 문제는 아니지만 LoadSceneAsync
의 경우 기다려온 후에 다른 시작 및 연속 순서가 발생합니다. 따라서 LoadSceneAsync.ToUniTask
사용하지 않는 것이 좋습니다.
참고 : Unity 2023.1 또는 새로 사용하는 경우
using UnityEngine;
새UnityEngine.Awaitable
메소드와 함께 작업 할 때 파일의 사용 명령문에서SceneManager.LoadSceneAsync
이는UnityEngine.AsyncOperation
버전의 사용을 피함으로써 컴파일 오류를 방지합니다.
StackTrace에서는 PlayerLoop에서 실행중인 위치를 확인할 수 있습니다.
기본적으로 Unitask의 PlayerLoop은 [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
에서 초기화됩니다.
BeforeCeneload에서 방법이 호출되는 순서는 비 결정적이므로 다른 BeforeCeneload 메소드에서 Unitask를 사용하려면이 전에 초기화해야합니다.
// AfterAssembliesLoaded is called before BeforeSceneLoad
[ RuntimeInitializeOnLoadMethod ( RuntimeInitializeLoadType . AfterAssembliesLoaded ) ]
public static void InitUniTaskLoop ( )
{
var loop = PlayerLoop . GetCurrentPlayerLoop ( ) ;
Cysharp . Threading . Tasks . PlayerLoopHelper . Initialize ( ref loop ) ;
}
Unity의 Entities
패키지를 가져 오면 BeforeSceneLoad
에서 사용자 정의 플레이어 루프를 기본적으로 재설정하고 ECS의 루프를 주입합니다. Unity가 Unitask의 초기화 방법 후 ECS의 주입 방법을 호출하면 Unitask가 더 이상 작동하지 않습니다.
이 문제를 해결하기 위해 ECS가 초기화 된 후 Unitask PlayerLoop를 다시 시작할 수 있습니다.
// Get ECS Loop.
var playerLoop = ScriptBehaviourUpdateOrder . CurrentPlayerLoop ;
// Setup UniTask's PlayerLoop.
PlayerLoopHelper . Initialize ( ref playerLoop ) ;
PlayerLoopHelper.IsInjectedUniTaskPlayerLoop()
호출하여 UnitASK의 플레이어 루프가 준비되었는지 여부를 진단 할 수 있습니다. 또한 PlayerLoopHelper.DumpCurrentPlayerLoop
모든 현재 플레이어 루프를 콘솔에 로그인합니다.
void Start ( )
{
UnityEngine . Debug . Log ( " UniTaskPlayerLoop ready? " + PlayerLoopHelper . IsInjectedUniTaskPlayerLoop ( ) ) ;
PlayerLoopHelper . DumpCurrentPlayerLoop ( ) ;
}
Unuse PlayerLooptiming Injection을 제거하여 루프 비용을 약간 최적화 할 수 있습니다. 초기화에서 PlayerLoopHelper.Initialize(InjectPlayerLoopTimings)
호출 할 수 있습니다.
var loop = PlayerLoop . GetCurrentPlayerLoop ( ) ;
PlayerLoopHelper . Initialize ( ref loop , InjectPlayerLoopTimings . Minimum ) ; // minimum is Update | FixedUpdate | LastPostLateUpdate
InjectPlayerLoopTimings
에는 3 개의 사전 설정, All
및 Standard
있습니다 (LastPostLateUpdate를 제외한 Last없이 모두), Minimum
( Update | FixedUpdate | LastPostLateUpdate
). 기본값은 모두이며 InjectPlayerLoopTimings.Update | InjectPlayerLoopTimings.FixedUpdate | InjectPlayerLoopTimings.PreLateUpdate
.
Microsoft.codeanAlysis.BannedApianAlyzers에서 주입되지 않은 PlayerLoopTiming
사용하는 데 오류가 발생할 수 있습니다. 예를 들어, InjectPlayerLoopTimings.Minimum
에 대해 이와 같은 BannedSymbols.txt
설정할 수 있습니다.
F:Cysharp.Threading.Tasks.PlayerLoopTiming.Initialization; Isn't injected this PlayerLoop in this project.
F:Cysharp.Threading.Tasks.PlayerLoopTiming.LastInitialization; Isn't injected this PlayerLoop in this project.
F:Cysharp.Threading.Tasks.PlayerLoopTiming.EarlyUpdate; Isn't injected this PlayerLoop in this project.
F:Cysharp.Threading.Tasks.PlayerLoopTiming.LastEarlyUpdate; Isn't injected this PlayerLoop in this project.d
F:Cysharp.Threading.Tasks.PlayerLoopTiming.LastFixedUpdate; Isn't injected this PlayerLoop in this project.
F:Cysharp.Threading.Tasks.PlayerLoopTiming.PreUpdate; Isn't injected this PlayerLoop in this project.
F:Cysharp.Threading.Tasks.PlayerLoopTiming.LastPreUpdate; Isn't injected this PlayerLoop in this project.
F:Cysharp.Threading.Tasks.PlayerLoopTiming.LastUpdate; Isn't injected this PlayerLoop in this project.
F:Cysharp.Threading.Tasks.PlayerLoopTiming.PreLateUpdate; Isn't injected this PlayerLoop in this project.
F:Cysharp.Threading.Tasks.PlayerLoopTiming.LastPreLateUpdate; Isn't injected this PlayerLoop in this project.
F:Cysharp.Threading.Tasks.PlayerLoopTiming.PostLateUpdate; Isn't injected this PlayerLoop in this project.
F:Cysharp.Threading.Tasks.PlayerLoopTiming.TimeUpdate; Isn't injected this PlayerLoop in this project.
F:Cysharp.Threading.Tasks.PlayerLoopTiming.LastTimeUpdate; Isn't injected this PlayerLoop in this project.
RS0030
심각도를 오류로 구성 할 수 있습니다.
async void
는 표준 C# 작업 시스템이므로 Unitask 시스템에서 실행되지 않습니다. 사용하지 않는 것이 좋습니다. async UniTaskVoid
는 가벼운 버전의 async UniTask
입니다. 왜냐하면 완료 가능한 완료가없고 오류를 즉시 UniTaskScheduler.UnobservedTaskException
에보고하지 않기 때문입니다. 기다릴 필요가 없다면 (화재 및 잊어 버리기) UniTaskVoid
사용하는 것이 좋습니다. 불행히도 경고를 기각하려면 Forget()
불러야합니다.
public async UniTaskVoid FireAndForgetMethod ( )
{
// do anything...
await UniTask . Yield ( ) ;
}
public void Caller ( )
{
FireAndForgetMethod ( ) . Forget ( ) ;
}
또한 Unitask에는 Forget
방법이 있으며 UniTaskVoid
와 유사하며 동일한 효과가 있습니다. 그러나 await
완전히 사용하지 않으면 UniTaskVoid
더 효율적입니다.
public async UniTask DoAsync ( )
{
// do anything...
await UniTask . Yield ( ) ;
}
public void Caller ( )
{
DoAsync ( ) . Forget ( ) ;
}
이벤트에 등록 된 비동기 람다를 사용하려면 async void
사용하지 마십시오. 대신 UniTask.Action
또는 UniTask.UnityAction
사용할 수 있으며, 둘 다 async UniTaskVoid
Lambda를 통해 대의원을 만듭니다.
Action actEvent ;
UnityAction unityEvent ; // especially used in uGUI
// Bad: async void
actEvent += async ( ) => { } ;
unityEvent += async ( ) => { } ;
// Ok: create Action delegate by lambda
actEvent += UniTask . Action ( async ( ) => { await UniTask . Yield ( ) ; } ) ;
unityEvent += UniTask . UnityAction ( async ( ) => { await UniTask . Yield ( ) ; } ) ;
UniTaskVoid
Monobehaviour의 Start
방법에도 사용할 수 있습니다.
class Sample : MonoBehaviour
{
async UniTaskVoid Start ( )
{
// async init code.
}
}
(누출) 유니 태스크를 확인하는 데 유용합니다. Window -> UniTask Tracker
.
UnitaskTracker는 추적을 활성화하고 스택 트레이스를 캡처하는 것이 유용하지만 성능이 큰 영향을 미치기 때문에 사용을 디버깅하기위한 것입니다. 권장 사용은 추적 및 스택 트레이스를 모두 수행하여 작업 누출을 찾아서 완료시 둘 다 비활성화하는 것입니다.
기본적으로 Unitask는 TextMeshPro ( BindTo(TMP_Text)
및 TMP_InputField
이벤트 확장, Standard UGUI InputField
), DOTPEIN ( Tween
AS AWEED) 및 주소 ( AsyncOperationHandle
및 AsyncOperationHandle<T>
)를 지원합니다.
UniTask.TextMeshPro
, UniTask.DOTween
, UniTask.Addressables
와 같은 분리 된 ASMDEF에 정의되어 있습니다.
TextMeshPro 및 주소 정보 지원은 패키지 관리자에서 패키지를 가져올 때 자동으로 활성화됩니다. 그러나 Dotween Support의 경우, Dotween Assets에서 가져온 후 스크립팅을 정의한 후 Syvail UNITASK_DOTWEEN_SUPPORT
정의를 사용하여 활성화합니다.
// sequential
await transform . DOMoveX ( 2 , 10 ) ;
await transform . DOMoveZ ( 5 , 20 ) ;
// parallel with cancellation
var ct = this . GetCancellationTokenOnDestroy ( ) ;
await UniTask . WhenAll (
transform . DOMoveX ( 10 , 3 ) . WithCancellation ( ct ) ,
transform . DOScale ( 10 , 3 ) . WithCancellation ( ct ) ) ;
Dotween Support의 기본 동작 ( await
, WithCancellation
, ToUniTask
)이 기다리고 있습니다. 트윈이 죽었습니다. 완전 (True/False) 및 Kill (True/False)에서 작동합니다. 그러나 트윈 ( SetAutoKill(false)
)을 재사용하려면 예상대로 작동하지 않습니다. 다른 타이밍을 기다리려면 다음과 같은 확장 방법이 Tween, AwaitForComplete
, AwaitForPause
, AwaitForPlay
, AwaitForRewind
, AwaitForStepComplete
에 존재합니다.
Unity 2020.2는 C# 8.0을 지원하므로 await foreach
사용할 수 있습니다. 이것은 비동기 시대의 새로운 업데이트 표기법입니다.
// Unity 2020.2, C# 8.0
await foreach ( var _ in UniTaskAsyncEnumerable . EveryUpdate ( ) . WithCancellation ( token ) )
{
Debug . Log ( " Update() " + Time . frameCount ) ;
}
C# 7.3 환경에서는 ForEachAsync
메소드를 사용하여 거의 같은 방식으로 작동 할 수 있습니다.
// C# 7.3(Unity 2018.3~)
await UniTaskAsyncEnumerable . EveryUpdate ( ) . ForEachAsync ( _ =>
{
Debug . Log ( " Update() " + Time . frameCount ) ;
} , token ) ;
.NET 9의 Task.WhenEach
과 유사한 UniTask.WhenEach
.
await foreach ( var result in UniTask . WhenEach ( task1 , task2 , task3 ) )
{
// The result is of type WhenEachResult<T>.
// It contains either `T Result` or `Exception Exception`.
// You can check `IsCompletedSuccessfully` or `IsFaulted` to determine whether to access `.Result` or `.Exception`.
// If you want to throw an exception when `IsFaulted` and retrieve the result when successful, use `GetResult()`.
Debug . Log ( result . GetResult ( ) ) ;
}
Unitaskasyncenumerable은 IObservable<T>
의 IEnumerable<T>
또는 rx와 유사한 비동기 Linq를 구현합니다. 모든 표준 LINQ 쿼리 연산자는 비동기 스트림에 적용 할 수 있습니다. 예를 들어, 다음 코드는 2 번 클릭 한 번씩 한 번씩 실행되는 버튼 클릭 비동기 스트림에 위치 필터를 적용하는 방법을 보여줍니다.
await okButton . OnClickAsAsyncEnumerable ( ) . Where ( ( x , i ) => i % 2 == 0 ) . ForEachAsync ( _ =>
{
} ) ;
Fire and Forget Style (예 : 이벤트 처리)은 Subscribe
사용할 수도 있습니다.
okButton . OnClickAsAsyncEnumerable ( ) . Where ( ( x , i ) => i % 2 == 0 ) . Subscribe ( _ =>
{
} ) ;
using Cysharp.Threading.Tasks.Linq;
및 UniTaskAsyncEnumerable
은 UniTask.Linq
asmdef에서 정의됩니다.
Unirx (반응성 확장)에 더 가깝지만 Unitaskasyncenumerable은 풀 기반 비동기 스트림이지만 RX는 푸시 기반 비동기 스트림이었습니다. 비슷하지만 특성은 다르고 세부 사항은 그들과 다르게 행동합니다.
UniTaskAsyncEnumerable
은 Enumerable
진입 점입니다. 표준 쿼리 연산자 외에도 EveryUpdate
, Timer
, TimerFrame
, Interval
, IntervalFrame
및 EveryValueChanged
와 같은 다른 발전기가 있습니다. 또한 Append
, Prepend
, DistinctUntilChanged
, ToHashSet
, Buffer
, CombineLatest
, Merge
Do
Never
ForEachAsync
TakeUntil
Pairwise
, Publish
, Queue
, Return
, SkipUntil
, SkipUntilCanceled
, TakeUntilCanceled
, TakeLast
, Subscribe
추가 된 추가 Unitask Original Query 연산자를 추가했습니다.
인수로서 func를 가진 방법에는 세 가지 추가 과부하가 있습니다. ***Await
***AwaitWithCancellation
.
Select ( Func < T , TR > selector )
SelectAwait ( Func < T , UniTask < TR > > selector )
SelectAwaitWithCancellation ( Func < T , CancellationToken , UniTask < TR > > selector )
func 내부의 async
메소드를 사용하려면 ***Await
또는 ***AwaitWithCancellation
사용하십시오.
비동기 반복기를 만드는 방법 : C# 8.0은 비동기 반복기 ( async yield return
)를 지원하지만 IAsyncEnumerable<T>
만 허용하며 C# 8.0 만 필요합니다. Unitask는 UniTaskAsyncEnumerable.Create
지원합니다.
// IAsyncEnumerable, C# 8.0 version of async iterator. ( do not use this style, IAsyncEnumerable is not controled in UniTask).
public async IAsyncEnumerable < int > MyEveryUpdate ( [ EnumeratorCancellation ] CancellationToken cancelationToken = default )
{
var frameCount = 0 ;
await UniTask . Yield ( ) ;
while ( ! token . IsCancellationRequested )
{
yield return frameCount ++ ;
await UniTask . Yield ( ) ;
}
}
// UniTaskAsyncEnumerable.Create and use `await writer.YieldAsync` instead of `yield return`.
public IUniTaskAsyncEnumerable < int > MyEveryUpdate ( )
{
// writer(IAsyncWriter<T>) has `YieldAsync(value)` method.
return UniTaskAsyncEnumerable . Create < int > ( async ( writer , token ) =>
{
var frameCount = 0 ;
await UniTask . Yield ( ) ;
while ( ! token . IsCancellationRequested )
{
await writer . YieldAsync ( frameCount ++ ) ; // instead of `yield return`
await UniTask . Yield ( ) ;
}
} ) ;
}
모든 ugui 구성 요소는 비동기 이벤트 스트림을 변환 할 수 있도록 ***AsAsyncEnumerable
구현합니다.
async UniTask TripleClick ( )
{
// In default, used button.GetCancellationTokenOnDestroy to manage lieftime of async
await button . OnClickAsync ( ) ;
await button . OnClickAsync ( ) ;
await button . OnClickAsync ( ) ;
Debug . Log ( " Three times clicked " ) ;
}
// more efficient way
async UniTask TripleClick ( )
{
using ( var handler = button . GetAsyncClickEventHandler ( ) )
{
await handler . OnClickAsync ( ) ;
await handler . OnClickAsync ( ) ;
await handler . OnClickAsync ( ) ;
Debug . Log ( " Three times clicked " ) ;
}
}
// use async LINQ
async UniTask TripleClick ( CancellationToken token )
{
await button . OnClickAsAsyncEnumerable ( ) . Take ( 3 ) . Last ( ) ;
Debug . Log ( " Three times clicked " ) ;
}
// use async LINQ2
async UniTask TripleClick ( CancellationToken token )
{
await button . OnClickAsAsyncEnumerable ( ) . Take ( 3 ) . ForEachAsync ( _ =>
{
Debug . Log ( " Every clicked " ) ;
} ) ;
Debug . Log ( " Three times clicked, complete. " ) ;
}
모든 monobehaviour 메시지 이벤트 이벤트 이벤트는 cysharp.threading.tasks.triggers를 사용하여 활성화 할 수있는 AsyncTriggers
로 비동기 스트림을 변환 할 수 있습니다 using Cysharp.Threading.Tasks.Triggers;
. Asynctrigger는 GetAsync***Trigger
사용하여 만들 수 있으며 자체를 UnitaskAsyncenumerable로 트리거합니다.
var trigger = this . GetOnCollisionEnterAsyncHandler ( ) ;
await trigger . OnCollisionEnterAsync ( ) ;
await trigger . OnCollisionEnterAsync ( ) ;
await trigger . OnCollisionEnterAsync ( ) ;
// every moves.
await this . GetAsyncMoveTrigger ( ) . ForEachAsync ( axisEventData =>
{
} ) ;
AsyncReactiveProperty
, AsyncReadOnlyReactiveProperty
는 Unitask의 ReactiveProperty 버전입니다. 결합 비동기 스트림 값에 대한 IUniTaskAsyncEnumerable<T>
의 BindTo
확장 방법 (Text/Selectable/TMP/Text).
var rp = new AsyncReactiveProperty < int > ( 99 ) ;
// AsyncReactiveProperty itself is IUniTaskAsyncEnumerable, you can query by LINQ
rp . ForEachAsync ( x =>
{
Debug . Log ( x ) ;
} , this . GetCancellationTokenOnDestroy ( ) ) . Forget ( ) ;
rp . Value = 10 ; // push 10 to all subscriber
rp . Value = 11 ; // push 11 to all subscriber
// WithoutCurrent ignore initial value
// BindTo bind stream value to unity components.
rp . WithoutCurrent ( ) . BindTo ( this . textComponent ) ;
await rp . WaitAsync ( ) ; // wait until next value set
// also exists ToReadOnlyAsyncReactiveProperty
var rp2 = new AsyncReactiveProperty < int > ( 99 ) ;
var rorp = rp . CombineLatest ( rp2 , ( x , y ) => ( x , y ) ) . ToReadOnlyAsyncReactiveProperty ( CancellationToken . None ) ;
풀 형 비동기 스트림은 시퀀스의 비동기 처리가 완료 될 때까지 다음 값을 얻지 못합니다. 이것은 버튼과 같은 푸시 형 이벤트의 데이터를 유출 할 수 있습니다.
// can not get click event during 3 seconds complete.
await button . OnClickAsAsyncEnumerable ( ) . ForEachAwaitAsync ( async x =>
{
await UniTask . Delay ( TimeSpan . FromSeconds ( 3 ) ) ;
} ) ;
유용하지만 (이중 클릭을 방지) 때때로 유용하지는 않습니다.
Queue()
메소드를 사용하면 비동기 처리 중에 이벤트가 이벤트를 큐에 넣습니다.
// queued message in asynchronous processing
await button . OnClickAsAsyncEnumerable ( ) . Queue ( ) . ForEachAwaitAsync ( async x =>
{
await UniTask . Delay ( TimeSpan . FromSeconds ( 3 ) ) ;
} ) ;
또는 Subscribe
, 화재 및 스타일을 잊어 버리십시오.
button . OnClickAsAsyncEnumerable ( ) . Subscribe ( async x =>
{
await UniTask . Delay ( TimeSpan . FromSeconds ( 3 ) ) ;
} ) ;
Channel
System.threading.tasks.channels와 동일합니다. golang 채널과 유사합니다.
현재 다중 프로듀서, 단일 소비자 언음되지 않은 채널 만 지원합니다. Channel.CreateSingleConsumerUnbounded<T>()
에 의해 생성 될 수 있습니다.
Producer ( .Writer
)의 경우 TryWrite
사용하여 값을 누르고 TryComplete
사용하여 채널을 완성하십시오. Consumer ( .Reader
)의 경우 TryRead
, WaitToReadAsync
, ReadAsync
, Completion
및 ReadAllAsync
사용하여 대기 메시지를 읽으십시오.
ReadAllAsync
IUniTaskAsyncEnumerable<T>
반환하여 LINQ 연산자를 쿼리합니다. 리더는 단일 소비자 만 허용하지만 .Publish()
쿼리 연산자를 사용하여 멀티 캐스트 메시지를 활성화합니다. 예를 들어, 펍/하위 유틸리티를 만드십시오.
public class AsyncMessageBroker < T > : IDisposable
{
Channel < T > channel ;
IConnectableUniTaskAsyncEnumerable < T > multicastSource ;
IDisposable connection ;
public AsyncMessageBroker ( )
{
channel = Channel . CreateSingleConsumerUnbounded < T > ( ) ;
multicastSource = channel . Reader . ReadAllAsync ( ) . Publish ( ) ;
connection = multicastSource . Connect ( ) ; // Publish returns IConnectableUniTaskAsyncEnumerable.
}
public void Publish ( T value )
{
channel . Writer . TryWrite ( value ) ;
}
public IUniTaskAsyncEnumerable < T > Subscribe ( )
{
return multicastSource ;
}
public void Dispose ( )
{
channel . Writer . TryComplete ( ) ;
connection . Dispose ( ) ;
}
}
Unity 6은 차단 가능한 유형을 소개합니다. 간단히 말해서, 기다릴 수있는 것은 유닛 ask의 서브 세트로 간주 될 수 있으며, 실제로 Awaitable의 디자인은 Unitask의 영향을 받았습니다. PlayerLoop 기반 대기 시간, 풀링 된 작업 및 비슷한 방식으로 취소 CancellationToken
통한 취소 지원을 처리 할 수 있어야합니다. 표준 라이브러리에 포함되면 Unitask를 계속 사용하거나 기다릴 수있는 것으로 마이그레이션 할 것인지 궁금 할 것입니다. 다음은 간단한 가이드입니다.
첫째, 차단 가능한 기능은 코 루틴이 제공하는 것과 동일합니다. yield return
대신 기다리고 있습니다. await NextFrameAsync()
대체합니다. yield return null
대체합니다. 그리고 WaitForSeconds
및 EndOfFrame
의 동등한 부분이 있습니다. 그러나 그 정도입니다. 기능 측면에서 코 루틴 기반이기 때문에 작업 기반 기능이 부족합니다. Async/Await을 사용한 실제 응용 프로그램 개발에서 WhenAll
과 같은 작업이 필수적입니다. 또한 Unitask를 사용하면 DelayFrame
과 같은 많은 프레임 기반 작업 및보다 유연한 PlayerLooptiming Control이 가능하며, 이는 사용할 수 없습니다. 물론 트래커 창도 없습니다.
따라서 응용 프로그램 개발을 위해 Unitask를 사용하는 것이 좋습니다. Unitask는 차단 가능한 슈퍼 세트이며 많은 필수 기능이 포함되어 있습니다. 외부 종속성을 피하려는 도서관 개발의 경우 방법에 대한 리턴 유형으로 바라볼 수있는 것이 적절합니다. AsUniTask
사용하여 AWAITABLE을 Unitask로 변환 할 수 있으므로 Unitask 라이브러리 내에서 차단 가능한 기반 기능을 처리하는 데 아무런 문제가 없습니다. 물론 의존성에 대해 걱정할 필요가 없다면, 유닛 ask를 사용하는 것이 라이브러리 개발에도 최선의 선택이 될 것입니다.
Unity의 [UnityTest]
속성은 Coroutine (ienumerator)을 테스트 할 수 있지만 비동기를 테스트 할 수는 없습니다. UniTask.ToCoroutine
Bridges Async/Coroutine으로 기다려서 비동기 방법을 테스트 할 수 있습니다.
[ UnityTest ]
public IEnumerator DelayIgnore ( ) => UniTask . ToCoroutine ( async ( ) =>
{
var time = Time . realtimeSinceStartup ;
Time . timeScale = 0.5f ;
try
{
await UniTask . Delay ( TimeSpan . FromSeconds ( 3 ) , ignoreTimeScale : true ) ;
var elapsed = Time . realtimeSinceStartup - time ;
Assert . AreEqual ( 3 , ( int ) Math . Round ( TimeSpan . FromSeconds ( elapsed ) . TotalSeconds , MidpointRounding . ToEven ) ) ;
}
finally
{
Time . timeScale = 1.0f ;
}
} ) ;
Unitask의 자체 단위 테스트는 CI와 통합하고 IL2CPP가 작동하는지 확인하기 위해 Unity Test Runner 및 Cysharp/RuntimeUnittestToolkit을 사용하여 작성됩니다.
대부분의 유닛 ask 메서드는 단일 스레드 (PlayerLoop)에서 실행되며, UniTask.Run
( Task.Run
동등한) 및 UniTask.SwitchToThreadPool
에서 스레드 풀에서 실행됩니다. 스레드 풀을 사용하는 경우 WebGL 등으로 작동하지 않습니다.
UniTask.Run
은 이제 더 이상 사용되지 않습니다. 대신 UniTask.RunOnThreadPool
사용할 수 있습니다. 또한 UniTask.Create
또는 UniTask.Void
사용할 수 있는지 고려하십시오.
Coroutine (ienumerator)을 Unitask로 변환하거나 직접 기다릴 수 있지만 몇 가지 제한 사항이 있습니다.
WaitForEndOfFrame
/ WaitForFixedUpdate
/ Coroutine
지원되지 않습니다.StartCoroutine
과 같지 않으며 지정된 PlayerLoopTiming
사용하며 Default PlayerLoopTiming.Update
는 Monobehaviour의 Update
및 StartCoroutine
의 루프 전에 실행됩니다. Coroutine에서 Async로 완전히 호환되는 경우 IEnumerator.ToUniTask(MonoBehaviour coroutineRunner)
과부하를 사용하십시오. 인수 Monobehaviour 인스턴스에서 STARTCOROUTINE을 실행하고 UnitASK에서 완료되기를 기다립니다.
Unitask는 편집기 Coroutine처럼 Unity 편집기에서 실행할 수 있습니다. 그러나 몇 가지 제한 사항이 있습니다.
DelayType.Realtime
으로 자동 변경하여 적절한 시간을 기다립니다.EditorApplication.update
에서 모든 PlayerLooptiming이 실행됩니다.-quit
가진 -batchmode
Unity가 EditorApplication.update
및 종료 된 후에 실행되지 않기 때문에 작동하지 않습니다. 대신, EditorApplication.Exit(0)
와 함께 -quit
사용하고 수동으로 종료하지 마십시오. Unitask에는 표준 작업과 같은 API가 많이 있습니다. 이 표는 대체 API가 무엇인지 보여줍니다.
표준 유형을 사용하십시오.
.NET 유형 | 유니astask 유형 |
---|---|
IProgress<T> | --- |
CancellationToken | --- |
CancellationTokenSource | --- |
유닛 ask 유형을 사용하십시오.
.NET 유형 | 유니astask 유형 |
---|---|
Task / ValueTask | UniTask |
Task<T> / ValueTask<T> | UniTask<T> |
async void | async UniTaskVoid |
+= async () => { } | UniTask.Void , UniTask.Action , UniTask.UnityAction |
--- | UniTaskCompletionSource |
TaskCompletionSource<T> | UniTaskCompletionSource<T> / AutoResetUniTaskCompletionSource<T> |
ManualResetValueTaskSourceCore<T> | UniTaskCompletionSourceCore<T> |
IValueTaskSource | IUniTaskSource |
IValueTaskSource<T> | IUniTaskSource<T> |
ValueTask.IsCompleted | UniTask.Status.IsCompleted() |
ValueTask<T>.IsCompleted | UniTask<T>.Status.IsCompleted() |
new Progress<T> | Progress.Create<T> |
CancellationToken.Register(UnsafeRegister) | CancellationToken.RegisterWithoutCaptureExecutionContext |
CancellationTokenSource.CancelAfter | CancellationTokenSource.CancelAfterSlim |
Channel.CreateUnbounded<T>(false){ SingleReader = true } | Channel.CreateSingleConsumerUnbounded<T> |
IAsyncEnumerable<T> | IUniTaskAsyncEnumerable<T> |
IAsyncEnumerator<T> | IUniTaskAsyncEnumerator<T> |
IAsyncDisposable | IUniTaskAsyncDisposable |
Task.Delay | UniTask.Delay |
Task.Yield | UniTask.Yield |
Task.Run | UniTask.RunOnThreadPool |
Task.WhenAll | UniTask.WhenAll |
Task.WhenAny | UniTask.WhenAny |
Task.WhenEach | UniTask.WhenEach |
Task.CompletedTask | UniTask.CompletedTask |
Task.FromException | UniTask.FromException |
Task.FromResult | UniTask.FromResult |
Task.FromCanceled | UniTask.FromCanceled |
Task.ContinueWith | UniTask.ContinueWith |
TaskScheduler.UnobservedTaskException | UniTaskScheduler.UnobservedTaskException |
Unitask는 적극적으로 적극적으로 비동기 약속 객체를 제로 할당을 달성하기 위해 적극적으로 캐시합니다 (기술적 인 세부 사항은 Blog Post Unitask v2 - 제로 할당 비동기/비동기 LINQ를 사용하여 기다리고 있음) 참조). 기본적으로 모든 약속을 캐시하지만 TaskPool.SetMaxPoolSize
값으로 구성 할 수 있습니다. 값은 유형 당 캐시 크기를 나타냅니다. TaskPool.GetCacheSizeInfo
현재 풀에서 캐시 된 객체를 반환합니다.
foreach ( var ( type , size ) in TaskPool . GetCacheSizeInfo ( ) )
{
Debug . Log ( type + " : " + size ) ;
}
UnityEditor에서 프로파일 러는 AsyncStateMachine 생성 컴파일러의 할당을 보여 주지만 디버그 (개발) 빌드에서만 발생합니다. C# 컴파일러는 디버그 빌드의 클래스 및 릴리스 빌드시 구조로 AsyncStateMachine을 생성합니다.
Unity는 2020.1 (오른쪽, 바닥 글)에서 시작하는 코드 최적화 옵션을 지원합니다.
C# 컴파일러 최적화를 변경하여 개발 빌드에서 AsyncStateMachine 할당을 제거하기 위해 릴리스 할 수 있습니다. 이 최적화 옵션은 Compilation.CompilationPipeline-codeOptimization
및 Compilation.CodeOptimization
통해 설정할 수도 있습니다.
Unity의 Default SynchronizationContext ( UnitySynchronizationContext
)는 성능 구현이 좋지 않습니다. Unitask는 SynchronizationContext
(및 ExecutionContext
)를 우회하여 사용하지 않지만 async Task
에 존재하는 경우 여전히 사용됩니다. UniTaskSynchronizationContext
는 성능에 더 나은 UnitySynchronizationContext
를 대체 한 것입니다.
public class SyncContextInjecter
{
[ RuntimeInitializeOnLoadMethod ( RuntimeInitializeLoadType . SubsystemRegistration ) ]
public static void Inject ( )
{
SynchronizationContext . SetSynchronizationContext ( new UniTaskSynchronizationContext ( ) ) ;
}
}
이것은 선택적 선택이며 항상 권장되는 것은 아닙니다. UniTaskSynchronizationContext
는 async UniTask
보다 성능이 떨어지며 완전한 유니ask 교체가 아닙니다. 또한 UnitySynchronizationContext
와의 전체 행동 적 호환성을 보장하지는 않습니다.
Unitask의 API 참조는 docfx 및 cysharp/docfxtemplate에 의해 cysharp.github.io/unitask에서 호스팅됩니다.
예를 들어, Unitask의 공장 방법은 Unitask#방법에서 볼 수 있습니다. Unitaskasyncenumerable의 공장/확장 방법은 Unitaskasyncenumerable#Methods에서 볼 수 있습니다.
GIT 패키지의 경로 쿼리 매개 변수를 지원하는 Unity 버전이 필요합니다 (Unity> = 2019.3.4f1, unity> = 2020.1a21). https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask
Package Manager에 추가 할 수 있습니다
또는 "com.cysharp.unitask": "https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask"
Packages/manifest.json
하십시오.
대상 버전을 설정하려면 Unitask는 *.*.*
릴리스 태그를 사용하여 #2.1.0
과 같은 버전을 지정할 수 있습니다. 예를 들어 https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask#2.1.0
입니다.
.NET 코어의 경우 Nuget을 사용하십시오.
PM> 설치 패키지 유닛 ask
.NET Core 버전의 Unitask는 PlayerLoop 종속 메소드가 제거 된 Unity Unitask의 하위 집합입니다.
표준 작업/valuetask보다 높은 성능으로 실행되지만 사용할 때 ExecutionContext/SynchronizationContext를 무시해야합니다. AsyncLocal
ExecutionContext를 무시하기 때문에 작동하지 않습니다.
내부적으로 Unitask를 사용하지만 Valuetask를 외부 API로 제공하는 경우 다음과 같이 쓸 수 있습니다 (Pooledawait에서 영감).
public class ZeroAllocAsyncAwaitInDotNetCore
{
public ValueTask < int > DoAsync ( int x , int y )
{
return Core ( this , x , y ) ;
static async UniTask < int > Core ( ZeroAllocAsyncAwaitInDotNetCore self , int x , int y )
{
// do anything...
await Task . Delay ( TimeSpan . FromSeconds ( x + y ) ) ;
await UniTask . Yield ( ) ;
return 10 ;
}
}
}
// UniTask does not return to original SynchronizationContext but you can use helper `ReturnToCurrentSynchronizationContext`.
public ValueTask TestAsync ( )
{
await using ( UniTask . ReturnToCurrentSynchronizationContext ( ) )
{
await UniTask . SwitchToThreadPool ( ) ;
// do anything..
}
}
.NET Core 버전은 Unity (예 : Cysharp/Magiconion)와 코드를 공유 할 때 사용자가 Unitask를 인터페이스로 사용할 수 있도록합니다. .NET Core 버전의 Unitask는 부드러운 코드 공유를 가능하게합니다.
유닛 ask에 해당하는 WhenAll과 같은 유틸리티 방법은 Cysharp/valuetasksupplement로 제공됩니다.
이 라이브러리는 MIT 라이센스에 따라 있습니다.