効率的な割り当てを無料で提供します。
UniTask<T>
およびカスタムAsyncmethodbuilderがゼロ割り当てを達成するUniTask.Yield
、 UniTask.Delay
、 UniTask.DelayFrame
など)技術的な詳細については、ブログ投稿を参照してください:Unitask V2 - Zero Allocation Async/await for unity、非同期linq
高度なヒントについては、ブログ投稿を参照してください:UnityWebRequestを非同期デコレータパターン - Unitaskの高度なテクニックを介して拡張
UPMパッケージを介して、GITリファレンスまたはアセットパッケージ( UniTask.*.*.*.unitypackage
// 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.4.13f1
Unity 2018.3
の後です。
なぜUnitask(カスタムタスクのようなオブジェクト)が必要なのですか?タスクは重すぎて、Unityスレッド(シングルスレッド)と一致していないためです。 Unityの非同期オブジェクトはUnityのエンジンレイヤーによって自動的に発送されるため、Unitaskはスレッドと同期Context/executionContextを使用しません。より速く、低い割り当てを達成し、統一と完全に統合されています。
非同期AsyncOperation
、 ResourceRequest
、 AssetBundleRequest
、 AssetBundleCreateRequest
、 UnityWebRequestAsyncOperation
、 AsyncGPUReadbackRequest
、 IEnumerator
などをusing Cysharp.Threading.Tasks;
場合、 。
Unitaskは、3つのパターンの拡張メソッドを提供します。
* await asyncOperation ;
* . WithCancellation ( CancellationToken ) ;
* . ToUniTask ( IProgress , PlayerLoopTiming , CancellationToken ) ;
WithCancellation
ToUniTask
の単純なバージョンであり、どちらもUniTask
を返します。キャンセルの詳細については、キャンセルと例外処理セクションを参照してください。
注:awaitはプレーヤーループのネイティブタイミングから直接返されますが、キャンセルとタウニタスクが指定されたプレーヤーループティミングから返されます。タイミングの詳細については、PlayerLoopセクションを参照してください。
注:AssetBundlereQuestには
asset
とallAssets
があり、デフォルトはasset
返します。allAssets
取得したい場合は、AwaitForAllAssets()
メソッドを使用できます。
UniTask
UniTask.WhenEach
タイプは、 UniTask.WhenAll
のUniTask.WhenAny
なユーティリティを使用できます。それらは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システムのみを使用する場合に役立ちます。
Unitaskは2回待つことができません。これは、.NET Standard 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メソッドには、 CancellationToken cancellationToken = default
パラメーターがあります。また、統一のための一部の非同期操作にはWithCancellation(CancellationToken)
とToUniTask(..., CancellationToken cancellation = default)
拡張メソッドがあります。
標準の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
または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
とは、非同期のライフサイクルを意味します。デフォルトの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でキャンセルトークンを追加します。
キャンセルが検出されると、すべての方法がOperationCanceledException
を投げ、上流に伝播します。例外( OperationCanceledException
に限定されない)がAsyncメソッドで処理されない場合、最終的にUniTaskScheduler.UnobservedTaskException
に伝播されます。受信した未処理の例外のデフォルトの動作は、例外としてログを記述することです。 UniTaskScheduler.UnobservedExceptionWriteLogType
を使用してログレベルを変更できます。カスタム動作を使用する場合は、 UniTaskScheduler.UnobservedTaskException.
また、 OperationCanceledException
は特別な例外であり、これはUnobservedTaskException
では静かに無視されます。
Async Unitaskメソッドで動作をキャンセルする場合は、手動で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
使用して、OperationCanceleDexceptionスローを避けてください。投げる代わりに(bool IsCanceled, T Result)
戻ります。
var ( isCanceled , _ ) = await UniTask . DelayFrame ( 10 , cancellationToken : cts . Token ) . SuppressCancellationThrow ( ) ;
if ( isCanceled )
{
// ...
}
注:ほとんどのソースメソッドに直接呼び出す場合にのみ、スローを抑制します。それ以外の場合、返品値は変換されますが、パイプライン全体がスローを抑制しません。
UniTask.Yield
やUniTask.Delay
など、Unityのプレーヤーループを使用するいくつかの機能は、プレーヤーループでキャンセルトークン状態を決定します。これは、 CancellationToken
が解雇されるとすぐにキャンセルされないことを意味します。
この動作を変更したい場合は、キャンセルを即時にするために、 cancelImmediately
-flagを引数として設定します。
await UniTask . Yield ( cancellationToken , cancelImmediately : true ) ;
注: cancelImmediately
to trueに設定し、即時のキャンセルを検出することは、デフォルトの動作よりも費用がかかります。これは、 CancellationToken.Register
を使用しているためです。プレーヤーループでキャンセルがかったことをチェックするよりも重いです。
タイムアウトはキャンセルのバリエーションです。 CancellationTokenSouce.CancelAfterSlim(TimeSpan)
でタイムアウトを設定し、CancellationTokenを非Yyncメソッドに渡すことができます。
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です。ただし、Unityでは、スレッドタイマーに依存するため、使用しないでください。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. " ) ;
}
}
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
を使用してください。この進捗工場には、2 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はカスタムプレーヤーループで実行されます。 Unitaskのプレーヤーループベースのメソッド( 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のデフォルトPlayerLoopに確認し、Unitaskのカスタムループを挿入できます。
PlayerLoopTiming.Update
はコルーチンのyield return null
に似ていますが、更新前に呼び出されます(更新とugui ScriptRunDelayedDynamicFrameRate
(button.onclickなど...)はScriptRunBehaviourUpdate
で呼び出されます。 PlayerLoopTiming.FixedUpdate
、 WaitForFixedUpdate
に似ています。
PlayerLoopTiming.LastPostLateUpdate
、Coroutineのyield return new WaitForEndOfFrame()
に相当するものではありません。 Coroutineのwaitforendofframeは、プレーヤーループが完了した後に実行されるようです。 Coroutineのフレームの端(Texture2D.ReadPixels
、ScreenCapture.CaptureScreenshotAsTexture
、CommandBuffer
など)が必要ないくつかの方法は、非同期/waintに置き換えたときに正しく機能しません。これらの場合、Monobehaviour(Coroutine Runnner)をUniTask.WaitForEndOfFrame
に渡します。たとえば、await UniTask.WaitForEndOfFrame(this);
軽量割り当て無料の代替手yield return new WaitForEndOfFrame()
。注:Unity 2023.1以降では、
await UniTask.WaitForEndOfFrame();
モノベハビアはもはや必要ありません。UnityEngine.Awaitable.EndOfFrameAsync
を使用します。
yield return null
とUniTask.Yield
は似ていますが、異なります。 yield return null
常に次のフレームを返しますが、 UniTask.Yield
次の呼び出しを返します。つまり、 UniTask.Yield(PlayerLoopTiming.Update)
PreUpdate
に呼び出し、同じフレームを返します。 UniTask.NextFrame()
次のフレームを返します。これは、 yield return null
とまったく同じ動作を期待できます。
unitask.yield(キャンセルトークンなし)は特別なタイプであり、
YieldAwaitable
を返し、lightrunnerで実行されます。それは最も軽量で最速です。
AsyncOperation
ネイティブタイミングから返されます。たとえば、await SceneManager.LoadSceneAsync
Start
EarlyUpdate.UpdatePreloading
から返されますEarlyUpdate.ScriptRunDelayedStartupFrame
また、 await UnityWebRequest
EarlyUpdate.ExecuteMainThreadJobs
から返されるのを待っています。
Unitaskでは、待望はネイティブタイミングを直接使用しますが、 WithCancellation
とToUniTask
使用して指定されたタイミングを使用します。これは通常、特定の問題ではありませんが、 LoadSceneAsync
では、待ち望んでから異なる順序の開始と継続を引き起こします。したがって、 LoadSceneAsync.ToUniTask
を使用しないことをお勧めします。
注:Unity 2023.1以降を使用する場合は、
using UnityEngine;
SceneManager.LoadSceneAsync
などの新しいUnityEngine.Awaitable
メソッドを使用するときのファイルのステートメントを使用する。これにより、UnityEngine.AsyncOperation
バージョンの使用を回避することにより、編集エラーが防止されます。
Stacktraceでは、PlayerLoopでのどこで動いているかを確認できます。
デフォルトでは、UnitaskのPlayerLoopは[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
で初期化されます。
beforesceneloadでメソッドが呼び出される順序は非決定論的であるため、他のbeferesceneloadメソッドでユニタスクを使用する場合は、この前に初期化してみてください。
// 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 ( ) ;
}
Unuss 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を除くすべてがありません)、 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
の軽量バージョンです。これは、ASYNC UNITASKの軽量バージョンであり、ASYNC UNITASKはASYNC UniTaskScheduler.UnobservedTaskException
の軽量であり、すぐにErrorsがすぐにエラーを報告しているためです。待ち(火と忘れる)を必要としない場合は、 UniTaskVoid
使用する方が良いです。残念ながら警告を却下するには、 Forget()
を呼び出す必要があります。
public async UniTaskVoid FireAndForgetMethod ( )
{
// do anything...
await UniTask . Yield ( ) ;
}
public void Caller ( )
{
FireAndForgetMethod ( ) . Forget ( ) ;
}
また、UnitaskにはForget
方法があり、 UniTaskVoid
に似ており、同じ効果があります。ただし、 UniTaskVoid
完全にawait
しない場合、より効率的です。
public async UniTask DoAsync ( )
{
// do anything...
await UniTask . Yield ( ) ;
}
public void Caller ( )
{
DoAsync ( ) . Forget ( ) ;
}
イベントに登録されたAsync Lambdaを使用するには、 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)
AsyncOperationHandle
TMP_InputField
AsyncOperationHandle<T>
InputField
機能をサポートしTween
。
UniTask.TextMeshPro
、 UniTask.DOTween
、 UniTask.Addressables
などの分離されたasmdefで定義されています。
Package Managerからパッケージをインポートする際に、TextMeshProおよびアドレスタブルサポートが自動的に有効になります。ただし、サポートの間では、dot -ween Assetsからインポートし、スクリプトを定義した後、シンボル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)の両方で機能します。ただし、Tweens( SetAutoKill(false)
)を再利用したい場合、予想どおりに機能しません。別のタイミングを待ち望んでいる場合、次の拡張メソッドがTweenに存在し、 AwaitForComplete
、 AwaitForPause
、 AwaitForPlay
、 AwaitForRewind
、 AwaitForStepComplete
。
Unity 2020.2はC#8.0をサポートしているため、 await foreach
使用できます。これは、ASYNC時代の新しい更新表記です。
// 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 ) ;
UniTask.WhenEach
それが.NET 9のTask.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は、 IEnumerable<T>
またはIObservable<T>
のrxに似た非同期linqを実装します。すべての標準LINQクエリ演算子は、非同期ストリームに適用できます。たとえば、次のコードは、2回のクリックに1回実行されるボタンクリック非同期ストリームにWhereフィルターを適用する方法を示しています。
await okButton . OnClickAsAsyncEnumerable ( ) . Where ( ( x , i ) => i % 2 == 0 ) . ForEachAsync ( _ =>
{
} ) ;
火と忘却のスタイル(たとえば、イベント処理)、 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
、 Pairwise
、 Publish
、 Queue
、 Return
、 SkipUntil
、 TakeUntil
、 SkipUntilCanceled
、 TakeUntilCanceled
、 TakeLast
、 Subscribe
などのUnitaskオリジナルクエリオペレーターが追加されました。
引数としてのFUNCを使用した方法には、3つの追加の過負荷があります***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のRacivePropertyのバージョンです。非同期ストリーム値をUnityコンポーネントに結合するためのIUniTaskAsyncEnumerable<T>
のBindTo
拡張方法(テキスト/選択可能/TMP/テキスト)。
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>()
で作成できます。
プロデューサー( .Writer
)の場合、 TryWrite
使用して値を押し、 TryComplete
使用してチャンネルを完了します。 Consumer( .Reader
)の場合、 TryRead
、 WaitToReadAsync
、 ReadAsync
、 Completion
、 ReadAllAsync
を使用して、キューに登録されたメッセージを読み取ります。
ReadAllAsync
、 IUniTaskAsyncEnumerable<T>
を返すため、linqオペレーターをクエリします。リーダーは単一消費者のみを許可しますが、 .Publish()
queryオペレーターを使用してマルチキャストメッセージを有効にします。たとえば、パブ/サブユーティリティを作成します。
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は、おもしろいタイプのAwaitableを紹介します。簡単に言えば、AwaitableはUnitaskのサブセットと見なすことができ、実際、AwaitableのデザインはUnitaskの影響を受けました。同様の方法で、キャンセルが鳴って、プレイヤーループベースの待望、プールされたタスク、 CancellationToken
のサポートを処理できるはずです。標準的なライブラリに含めることで、Unitaskの使用を続けているのか、それともAwaitableに移行するのか疑問に思うかもしれません。これが簡単なガイドです。
第一に、Awaitableが提供する機能は、Coroutinesが提供するものと同等です。 yield return
の代わりに、待ち望みを使用します。 await NextFrameAsync()
yield return null
また、 WaitForSeconds
とEndOfFrame
に相当するものがあります。しかし、それはそれの範囲です。機能性の観点からコルーチンベースであるため、タスクベースの機能がありません。 ASYNC/待ち望を使用した実際のアプリケーション開発では、 WhenAll
のような操作が不可欠です。さらに、Unitaskは、多くのフレームベースの操作( DelayFrame
など)およびより柔軟なPlayerLooptimingコントロールを有効にします。もちろん、トラッカーウィンドウもありません。
したがって、アプリケーション開発にUnitaskを使用することをお勧めします。 UnitaskはAwaitableのスーパーセットであり、多くの重要な機能が含まれています。ライブラリ開発の場合、外部の依存関係を回避したい場合、Awaitableをメソッドのリターンタイプとして使用することが適切です。 asunitaskを使用してAsUniTask
を使用してUnitaskに変換できるため、Unitaskライブラリ内で待機可能ベースの機能を処理することに問題はありません。もちろん、依存関係について心配する必要がない場合は、Unitaskを使用することが図書館の開発にも最適です。
Unityの[UnityTest]
属性は、Coroutine(IENumerator)をテストできますが、非同期をテストすることはできません。 UniTask.ToCoroutine
ブリッジアシン/コロウチンに待ち望んでいるので、非同期メソッドをテストできます。
[ 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独自のユニットテストは、UnityテストランナーとCysharp/RuntimeTimeIttestToolkitを使用して書かれており、CIと統合し、IL2CPPが機能しているかどうかを確認します。
ほとんどのUnitaskメソッドは、単一のスレッド(playerloop)で実行され、 UniTask.Run
( Task.Run
等価)とUniTask.SwitchToThreadPool
のみがスレッドプールで実行されます。スレッドプールを使用する場合、WebGLなどでは機能しません。
UniTask.Run
廃止されました。代わりにUniTask.RunOnThreadPool
使用できます。また、 UniTask.Create
またはUniTask.Void
を使用できるかどうかを検討してください。
Coroutine(Ienumerator)をUnitask(または直接待ちます)に変換できますが、いくつかの制限があります。
WaitForEndOfFrame
/ WaitForFixedUpdate
/ Coroutine
サポートされていません。StartCoroutine
と同じではありません。指定されたPlayerLoopTiming
使用し、デフォルトのPlayerLoopTiming.Update
はMonobehaviourのUpdate
とStartCoroutine
のループの前に実行されます。 CoroutineからAsyncへの完全に互換性のある変換が必要な場合は、 IEnumerator.ToUniTask(MonoBehaviour coroutineRunner)
オーバーロードを使用してください。 Monobehaviourの引数のインスタンスでStartCoroutineを実行し、Unitaskで完了するのを待ちます。
Unitaskは、編集者CoroutineのようにUnity Editorで実行できます。ただし、いくつかの制限があります。
DelayType.Realtime
に変更します。EditorApplication.update
で実行されます。EditorApplication.update
実行しないため、 -quit
をwith with withで-batchmode
、単一のフレームの後に終了します。代わりに、 EditorApplication.Exit(0)
で-quit
使用して手動で終了しないでください。 Unitaskには、多くの標準的なタスクのようなAPIがあります。この表は、代替APIが何であるかを示しています。
標準タイプを使用します。
.NETタイプ | ユニタスクタイプ |
---|---|
IProgress<T> | --- |
CancellationToken | --- |
CancellationTokenSource | --- |
ユニタスクタイプを使用します。
.NETタイプ | ユニタスクタイプ |
---|---|
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は積極的にasyncを約束してゼロ割り当てを達成するためにオブジェクトを約束します(技術的な詳細については、ブログ投稿Unitask v2 - ゼロ割り当てAsync/async/async/await for unity、非同期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のデフォルトの同期Context( 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
よりもパフォーマンスが低く、完全なユニタスクの交換ではありません。また、 UnitySynchronizationContext
との完全な行動互換性を保証するものではありません。
UnitaskのAPI参照は、docfxおよびcysharp/docfxtemplateによってcysharp.github.io/unitaskでホストされています。
たとえば、Unitaskの工場の方法は、Unitask#Methodで見ることができます。 Unitaskasyncenumerableの工場/拡張メソッドは、Unitaskasyncenumerable#メソッドで見ることができます。
GitパッケージのパスクエリパラメーターをサポートするUnityのバージョンが必要です(Unity> = 2019.3.4F1、Unity> = 2020.1A21)。 https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask
パッケージマネージャーに追加できます
または、 "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
unitask/assets/plugins/unitask#2.1.0。
.NET Coreの場合、Nugetを使用します。
PM>インストールパッケージユニットアスク
.NETコアバージョンのユニタスクは、プレーヤーループに従ったメソッドが削除されたUnity Unitaskのサブセットです。
標準のタスク/ValuetAskよりも高いパフォーマンスで実行されますが、使用するときはexecutionContext/SynchronizationContextを無視するように注意する必要があります。 AsyncLocal
、executioncontextを無視するためも機能しません。
Unitaskを内部的に使用しているが、Valuetaskを外部APIとして提供する場合は、次のように書くことができます(Poodawaitに触発されています)。
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コアバージョンは、Unity(Cysharp/Magiconionなど)とコードを共有するときに、ユーザーがインターフェイスとしてUnitaskを使用できるようにすることを目的としています。 .NET CoreバージョンのUnitaskは、スムーズなコード共有を有効にします。
Unitaskに相当するWhenallなどのユーティリティ方法は、Cysharp/ValuetAsksupplementとして提供されます。
このライブラリはMITライセンスの下にあります。