Fournit une intégration asynchrone / attente sans allocation efficace pour l'unité.
UniTask<T>
et AsyncMethodBuilder personnalisé pour obtenir une allocation zéroUniTask.Yield
, UniTask.Delay
, UniTask.DelayFrame
, etc.) qui permettent de remplacer toutes les opérations de coroutine Pour plus de détails techniques, voir Blog Article: Unitask V2 - ALLOCE ZERO ASYNC / AWAIT for Unity, avec Asynchronous Linq
Pour des conseils avancés, voir Article de blog: étend UnityWebRequest via le modèle de décorateur asynchrone - Techniques avancées de Unitask
Installez via le package UPM avec référence GIT ou package d'actifs ( UniTask.*.*.*.unitypackage
) disponible en Unitask / Releases.
// 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 " ) ;
}
Les fonctionnalités Unitask reposent sur C # 7.0 (fonctionnalité de méthode asynchrone personnalisée de type tâche), donc la version Unity requise est après Unity 2018.3
, la version la plus basse officielle prise en charge est Unity 2018.4.13f1
.
Pourquoi Unitask (objet de type tâche personnalisé) est-il requis? Parce que la tâche est trop lourde et ne correspond pas au filetage d'Unity (un seul fil). Unitask n'utilise pas de threads et de synchronisation Context / ExecutionContext car l'objet asynchrone d'Unity est automatiquement envoyé par la couche moteur d'Unity. Il atteint une allocation plus rapide et inférieure, et est complètement intégré à l'unité.
Vous pouvez attendre AsyncOperation
, ResourceRequest
, AssetBundleRequest
, AssetBundleCreateRequest
, UnityWebRequestAsyncOperation
, AsyncGPUReadbackRequest
, IEnumerator
et autres lorsque using Cysharp.Threading.Tasks;
.
Unitask fournit trois modèles de méthodes d'extension.
* await asyncOperation ;
* . WithCancellation ( CancellationToken ) ;
* . ToUniTask ( IProgress , PlayerLoopTiming , CancellationToken ) ;
WithCancellation
est une version simple de ToUniTask
, les deux UniTask
de retour. Pour plus de détails sur l'annulation, voir: Section d'annulation et de gestion des exceptions.
Remarque: L'attente est directement retournée du timing natif de PlayerLoop, mais la réduction et le tounitask sont retournés de PlayerLooptiming spécifié. Pour plus de détails sur le timing, voir: Section Playerloop.
Remarque: AssetBundleRequest a
asset
etallAssets
, par défaut attend des retoursasset
. Si vous souhaitez obtenirallAssets
, vous pouvez utiliser la méthodeAwaitForAllAssets()
.
Le type d' UniTask
peut utiliser des services publics comme UniTask.WhenAll
. WHENALL, UniTask.WhenAny
, UniTask.WhenEach
. Ils sont comme Task.WhenAll
/ Task.WhenAny
, mais le type de retour est plus utile. Ils renvoient des tuples de valeur afin que vous puissiez déconstruire chaque résultat et passer plusieurs types.
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 ) ;
}
Si vous souhaitez convertir un rappel en Unitask, vous pouvez utiliser UniTaskCompletionSource<T>
qui est une édition légère de TaskCompletionSource<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>
}
Vous pouvez convertir la tâche -> Unitask: AsUniTask
, UniTask
-> UniTask<AsyncUnit>
: AsAsyncUnitUniTask
, UniTask<T>
-> UniTask
: AsUniTask
. UniTask<T>
-> Le coût de conversion de UniTask
est gratuit.
Si vous souhaitez convertir l'async en coroutine, vous pouvez utiliser .ToCoroutine()
, cela est utile si vous souhaitez uniquement permettre d'utiliser le système Coroutine.
Unitask ne peut pas attendre deux fois. Il s'agit d'une contrainte similaire à la ValueTask / IvalUetAsksource introduite dans .NET Standard 2.1.
Les opérations suivantes ne doivent jamais être effectuées sur une instance Valutask:
- En attente de l'instance plusieurs fois.
- Appeler Astak plusieurs fois.
- Utilisation de .Result ou .getAwaitter (). GetResult () lorsque l'opération ne s'est pas encore terminée, ou les utilisant plusieurs fois.
- Utiliser plus d'une de ces techniques pour consommer l'instance.
Si vous effectuez l'un des éléments ci-dessus, les résultats ne sont pas définis.
var task = UniTask . DelayFrame ( 10 ) ;
await task ;
await task ; // NG, throws Exception
Stockez dans le champ de classe, vous pouvez utiliser UniTask.Lazy
qui prend en charge les appels plusieurs fois. .Preserve()
permet plusieurs appels (résultats mis en cache en interne). Ceci est utile lorsqu'il y a plusieurs appels dans une portée de fonction.
UniTaskCompletionSource
peut également attendre plusieurs fois et attendre de nombreux appelants.
Certaines méthodes d'usine unitask ont un paramètre CancellationToken cancellationToken = default
. De plus, certaines opérations asynchrones pour l'unité ont WithCancellation(CancellationToken)
et ToUniTask(..., CancellationToken cancellation = default)
.
Vous pouvez passer CancellationToken
au paramètre par CancellationTokenSource
standardtokensource.
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 ) ;
CANCELLATIONTOKINE peut être créé par CancellationTokenSource
ou la méthode d'extension de Monobehaviour GetCancellationTokenOnDestroy
.
// this CancellationToken lifecycle is same as GameObject.
await UniTask . DelayFrame ( 1000 , cancellationToken : this . GetCancellationTokenOnDestroy ( ) ) ;
Pour l'annulation du propage, toute la méthode asynchrone recommande d'accepter CancellationToken cancellationToken
à la dernière argument et de passer CancellationToken
de la racine à la fin.
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
signifie le cycle de vie de l'async. Vous pouvez tenir votre propre cycle de vie à la place de l'annulation par défaut de l'annulation.
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 ( ) ;
}
}
Après Unity 2022.2, Unity ajoute l'annulation du monobehaviour.DestroycancellationToken et Application.ExitCancellationToken.
Lorsque l'annulation est détectée, toutes les méthodes lancent OperationCanceledException
et se propagent en amont. Lorsque l'exception (non limitée à OperationCanceledException
) n'est pas gérée dans la méthode asynchronisée, elle se propage enfin à UniTaskScheduler.UnobservedTaskException
. Le comportement par défaut de l'exception non perdue reçue consiste à écrire le journal comme exception. Le niveau de journal peut être modifié à l'aide de UniTaskScheduler.UnobservedExceptionWriteLogType
. Si vous souhaitez utiliser un comportement personnalisé, définissez une action sur UniTaskScheduler.UnobservedTaskException.
Et OperationCanceledException
est également une exception particulière, celle-ci est silencieusement ignorée chez UnobservedTaskException
.
Si vous souhaitez annuler le comportement dans une méthode Async Unitask, lancez manuellement OperationCanceledException
.
public async UniTask < int > FooAsync ( )
{
await UniTask . Yield ( ) ;
throw new OperationCanceledException ( ) ;
}
Si vous gérez une exception mais que vous souhaitez ignorer (propager à la manipulation globale d'annulation), utilisez un filtre d'exception.
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 ;
}
}
lance / catch OperationCanceledException
est légèrement lourd, donc si les performances sont une préoccupation, utilisez UniTask.SuppressCancellationThrow
pour éviter le lancer OperationCanceLeledException. Il revient (bool IsCanceled, T Result)
au lieu de lancer.
var ( isCanceled , _ ) = await UniTask . DelayFrame ( 10 , cancellationToken : cts . Token ) . SuppressCancellationThrow ( ) ;
if ( isCanceled )
{
// ...
}
Remarque: supprimez uniquement les lancers si vous appelez directement dans la méthode la plus source. Sinon, la valeur de retour sera convertie, mais l'ensemble du pipeline ne supprimera pas les lancers.
Certaines fonctionnalités qui utilisent la boucle de lecteur d'Unity, telles que UniTask.Yield
et UniTask.Delay
etc., détermine l'état d'annulation de l'annulation sur la boucle du joueur. Cela signifie qu'il n'annule pas immédiatement après CancellationToken
.
Si vous souhaitez modifier ce comportement, l'annulation est immédiate, définissez l'indicateur cancelImmediately
en tant qu'argument.
await UniTask . Yield ( cancellationToken , cancelImmediately : true ) ;
Remarque: la définition de cancelImmediately
de True et la détection d'une annulation immédiate est plus coûteuse que le comportement par défaut. En effet, il utilise CancellationToken.Register
; Il est plus lourd que de vérifier l'annulation de l'annulation sur la boucle du joueur.
Le délai d'attente est une variation d'annulation. Vous pouvez définir le délai d'attente par CancellationTokenSouce.CancelAfterSlim(TimeSpan)
et passer l'annulation des méthodes asynchrones.
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
est une API standard. Cependant, dans Unity, vous ne devez pas l'utiliser car il dépend de la minuterie de filetage.CancelAfterSlim
est les méthodes d'extension d'Unitask, il utilise Playerloop à la place.
Si vous souhaitez utiliser le délai d'attente avec une autre source d'annulation, utilisez 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. " ) ;
}
}
Optimiser pour réduire l'allocation de l'annulation de l'annulation de la méthode du délai d'appel par appel, vous pouvez utiliser TimeoutController
d'Unitask.
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 " ) ;
}
}
}
Si vous souhaitez utiliser le délai d'attente avec une autre source d'annulation, utilisez new TimeoutController(CancellationToken)
.
TimeoutController timeoutController ;
CancellationTokenSource clickCancelSource ;
void Start ( )
{
this . clickCancelSource = new CancellationTokenSource ( ) ;
this . timeoutController = new TimeoutController ( clickCancelSource ) ;
}
Remarque: Unitask a .Timeout
, .TimeoutWithoutException
Méthodes Cependant, si possible, ne les utilisez pas, veuillez passer CancellationToken
. Parce que .Timeout
fonctionne à partir de la tâche externe, ne peut pas arrêter la tâche de délai d'attente. .Timeout
signifie ignorer le résultat lors du délai d'attente. Si vous passez un CancellationToken
à la méthode, il agira de l'intérieur de la tâche, il est donc possible d'arrêter une tâche d'exécution.
Certaines opérations asynchrones pour Unity ont des méthodes d'extension 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 ) ;
Vous ne devez pas utiliser new System.Progress<T>
, car il provoque une allocation à chaque fois. Utilisez à la place Cysharp.Threading.Tasks.Progress
. Cette usine de progrès possède deux méthodes, Create
et CreateOnlyValueChanged
. CreateOnlyValueChanged
appelle uniquement lorsque la valeur de progression a changé.
La mise en œuvre de l'interface iProgress à l'appelant est meilleure car il n'y a pas d'allocation lambda.
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 est exécuté sur un joueur personnalisé. Les méthodes basées sur PlayerLoop d'Unitask (telles que Delay
, DelayFrame
, asyncOperation.ToUniTask
, etc ...) acceptent ce 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
}
Il indique quand s'exécuter, vous pouvez vérifier PlayerLoopList.md vers Playerloop par défaut d'Unity et la boucle personnalisée d'Unitask injectée.
PlayerLoopTiming.Update
est similaire à yield return null
dans une coroutine, mais il est appelé avant la mise à jour (les événements de mise à jour et ugui (Button.Onclick, etc ...) sont appelés sur ScriptRunBehaviourUpdate
, le rendement null est appelé ScriptRunDelayedDynamicFrameRate
). PlayerLoopTiming.FixedUpdate
est similaire à WaitForFixedUpdate
.
PlayerLoopTiming.LastPostLateUpdate
n'est pas équivalent auyield return new WaitForEndOfFrame()
. WaitForrendOfframe de Coroutine semble fonctionner après la fin du Playerloop. Certaines méthodes qui nécessitent la fin du cadre de Coroutine (Texture2D.ReadPixels
,ScreenCapture.CaptureScreenshotAsTexture
,CommandBuffer
, etc.) ne fonctionnent pas correctement lorsqu'elles sont remplacées par Async / Await. Dans ces cas, passez Monobehaviour (Coroutine Runnner) àUniTask.WaitForEndOfFrame
. Par exemple,await UniTask.WaitForEndOfFrame(this);
Est-ce que l'allocation légère alternative gratuite deyield return new WaitForEndOfFrame()
.Remarque: Dans Unity 2023.1 ou plus récent,
await UniTask.WaitForEndOfFrame();
Ne nécessite plus le monobehaviour. Il utiliseUnityEngine.Awaitable.EndOfFrameAsync
.
yield return null
et UniTask.Yield
sont similaires mais différents. yield return null
Renvoie toujours le cadre suivant mais UniTask.Yield
revient ensuite appelé. Autrement dit, appelez UniTask.Yield(PlayerLoopTiming.Update)
sur PreUpdate
, il renvoie le même cadre. UniTask.NextFrame()
garantit le rendement suivant la trame suivante, vous pouvez vous attendre à ce que cela se comporte exactement de la même manière que yield return null
.
Unitask.yield (sans annulationtoken) est un type spécial, renvoie
YieldAwaitable
et fonctionne sur le rendement. C'est le plus léger et le plus rapide.
AsyncOperation
est retournée du timing natif. Par exemple, Await SceneManager.LoadSceneAsync
est retourné de EarlyUpdate.UpdatePreloading
et après avoir été appelé, le Start
de la scène chargée est appelé de EarlyUpdate.ScriptRunDelayedStartupFrame
. await UnityWebRequest
est renvoyé de EarlyUpdate.ExecuteMainThreadJobs
.
Dans Unitask, Await utilise directement le timing natif, tandis que WithCancellation
et ToUniTask
utilisent un timing spécifié. Ce n'est généralement pas un problème particulier, mais avec LoadSceneAsync
, il provoque un ordre de début et de continuation différent après l'attente. Il est donc recommandé de ne pas utiliser LoadSceneAsync.ToUniTask
.
Remarque: Lorsque vous utilisez Unity 2023.1 ou plus récent, assurez-vous que vous
using UnityEngine;
Dans les instructions d'utilisation de votre fichier lorsque vous travaillez avec de nouvelles méthodesUnityEngine.Awaitable
commeSceneManager.LoadSceneAsync
. Cela empêche les erreurs de compilation en évitant l'utilisation de la versionUnityEngine.AsyncOperation
.
Dans le StackTrace, vous pouvez vérifier où il fonctionne dans Playerloop.
Par défaut, PlayerLoop d'Unitask est initialisé sur [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
.
L'ordre dans lequel les méthodes sont appelées dans BeforeScenoad est non déterministe, donc si vous souhaitez utiliser unitask dans d'autres méthodes Beforesceload, vous devriez essayer de l'initialiser avant cela.
// AfterAssembliesLoaded is called before BeforeSceneLoad
[ RuntimeInitializeOnLoadMethod ( RuntimeInitializeLoadType . AfterAssembliesLoaded ) ]
public static void InitUniTaskLoop ( )
{
var loop = PlayerLoop . GetCurrentPlayerLoop ( ) ;
Cysharp . Threading . Tasks . PlayerLoopHelper . Initialize ( ref loop ) ;
}
Si vous importez le package Entities
d'Unity, qui réinitialise la boucle de joueur personnalisée par défaut sur BeforeSceneLoad
et injecte la boucle d'ECS. Lorsque Unity appelle la méthode injecte d'ECS après la méthode d'initialisation d'Unitask, Unitask ne fonctionnera plus.
Pour résoudre ce problème, vous pouvez réinitialiser l'unité Playerloop après l'initialisation des ECS.
// Get ECS Loop.
var playerLoop = ScriptBehaviourUpdateOrder . CurrentPlayerLoop ;
// Setup UniTask's PlayerLoop.
PlayerLoopHelper . Initialize ( ref playerLoop ) ;
Vous pouvez diagnostiquer si la boucle de joueur d'Unitask est prête en appelant PlayerLoopHelper.IsInjectedUniTaskPlayerLoop()
. Et aussi PlayerLoopHelper.DumpCurrentPlayerLoop
enregistre tous les joueurs actuels pour consoler.
void Start ( )
{
UnityEngine . Debug . Log ( " UniTaskPlayerLoop ready? " + PlayerLoopHelper . IsInjectedUniTaskPlayerLoop ( ) ) ;
PlayerLoopHelper . DumpCurrentPlayerLoop ( ) ;
}
Vous pouvez optimiser légèrement le coût de la boucle en supprimant l'injection non utilisée par le joueur. Vous pouvez appeler PlayerLoopHelper.Initialize(InjectPlayerLoopTimings)
sur Initialize.
var loop = PlayerLoop . GetCurrentPlayerLoop ( ) ;
PlayerLoopHelper . Initialize ( ref loop , InjectPlayerLoopTimings . Minimum ) ; // minimum is Update | FixedUpdate | LastPostLateUpdate
InjectPlayerLoopTimings
a trois préréglages, All
et Standard
(tous sans dernier sauf LastPostlateUpdate), Minimum
( Update | FixedUpdate | LastPostLateUpdate
). La valeur par défaut est tout et vous pouvez combiner des synchronisation d'injects personnalisés comme InjectPlayerLoopTimings.Update | InjectPlayerLoopTimings.FixedUpdate | InjectPlayerLoopTimings.PreLateUpdate
.
Vous pouvez faire une erreur pour utiliser PlayerLoopTiming
non injecté par Microsoft.codeanalysis.Bannedapianalysers. Par exemple, vous pouvez configurer BannedSymbols.txt
comme celui-ci pour InjectPlayerLoopTimings.Minimum
.
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.
Vous pouvez configurer la gravité RS0030
à l'erreur.
async void
est un système de tâches C # standard, il ne fonctionne donc pas sur les systèmes unitask. Il vaut mieux ne pas l'utiliser. async UniTaskVoid
est une version légère d' async UniTask
car elle n'a pas d'erreurs d'achèvement et de rapports immédiatement à UniTaskScheduler.UnobservedTaskException
. Si vous n'avez pas besoin d'attendre (feu et oublier), l'utilisation UniTaskVoid
est meilleure. Malheureusement pour rejeter l'avertissement, vous devez appeler Forget()
.
public async UniTaskVoid FireAndForgetMethod ( )
{
// do anything...
await UniTask . Yield ( ) ;
}
public void Caller ( )
{
FireAndForgetMethod ( ) . Forget ( ) ;
}
L'unité a également la méthode Forget
, elle est similaire à UniTaskVoid
et a les mêmes effets. Cependant, UniTaskVoid
est plus efficace si vous n'utilisez pas complètement await
。
public async UniTask DoAsync ( )
{
// do anything...
await UniTask . Yield ( ) ;
}
public void Caller ( )
{
DoAsync ( ) . Forget ( ) ;
}
Pour utiliser un Lambda asynchrone enregistré pour un événement, n'utilisez pas async void
. Au lieu de cela, vous pouvez utiliser UniTask.Action
ou UniTask.UnityAction
, qui créent tous deux un délégué via 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
peut également être utilisé dans la méthode Start
de Monobehaviour.
class Sample : MonoBehaviour
{
async UniTaskVoid Start ( )
{
// async init code.
}
}
Utile pour la vérification (divulguée) des œuvres. Vous pouvez ouvrir la fenêtre du tracker dans Window -> UniTask Tracker
.
UnitaskTracker est destiné à le débogage d'utilisation uniquement comme permettant le suivi et la capture de Stacktraces est utile mais a un impact sur les performances lourdes. L'utilisation recommandée consiste à permettre à la fois le suivi et le stacktraces pour trouver des fuites de tâches et les désactiver les deux une fois terminé.
Par défaut, Unitask prend en charge TextMeshPro ( BindTo(TMP_Text)
et TMP_InputField
Event Extensions comme Standard UGUI InputField
), Dotween ( Tween
As Awaitable) et Addressables ( AsyncOperationHandle
et AsyncOperationHandle<T>
Aussi Awaitable).
Il est défini dans ASMDEF séparé comme UniTask.TextMeshPro
, UniTask.DOTween
, UniTask.Addressables
.
La prise en charge de TextMeshPro et d'adressables est automatiquement activée lors de l'importation de leurs packages depuis Package Manager. Cependant, pour le support Dotween, après l'importation des actifs Dotween et définissez le script de définir le symbole UNITASK_DOTWEEN_SUPPORT
pour l'activer.
// 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 ) ) ;
Le comportement par défaut de Dotween Support ( await
, WithCancellation
, ToUniTask
) attend que Tween soit tué. Il fonctionne à la fois sur complet (true / false) et kill (true / false). Mais si vous souhaitez réutiliser les préadolescents ( SetAutoKill(false)
), cela ne fonctionne pas comme prévu. Si vous souhaitez vous attendre pour un autre timing, les méthodes d'extension suivantes existent dans Tween, AwaitForComplete
, AwaitForPause
, AwaitForPlay
, AwaitForRewind
, AwaitForStepComplete
.
Unity 2020.2 prend en charge C # 8.0 afin que vous puissiez utiliser await foreach
. Il s'agit de la nouvelle notation de mise à jour à l'ère asynchrone.
// Unity 2020.2, C# 8.0
await foreach ( var _ in UniTaskAsyncEnumerable . EveryUpdate ( ) . WithCancellation ( token ) )
{
Debug . Log ( " Update() " + Time . frameCount ) ;
}
Dans un environnement C # 7.3, vous pouvez utiliser la méthode ForEachAsync
pour fonctionner presque de la même manière.
// C# 7.3(Unity 2018.3~)
await UniTaskAsyncEnumerable . EveryUpdate ( ) . ForEachAsync ( _ =>
{
Debug . Log ( " Update() " + Time . frameCount ) ;
} , token ) ;
UniTask.WhenEach
qui est similaire à Task.WhenEach
de .NET 9.Lorsque peut consommer une nouvelle façon d'attendre plusieurs tâches.
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 ( ) ) ;
}
Unitaskasyncenumable implémente Linq asynchrone, similaire à LINQ dans IEnumerable<T>
ou RX dans IObservable<T>
. Tous les opérateurs de requête LINQ standard peuvent être appliqués aux flux asynchrones. Par exemple, le code suivant montre comment appliquer un filtre où un flux asynchrone cliquez sur un bouton qui s'exécute une fois tous les deux clics.
await okButton . OnClickAsAsyncEnumerable ( ) . Where ( ( x , i ) => i % 2 == 0 ) . ForEachAsync ( _ =>
{
} ) ;
Fire and Forget Style (par exemple, manipulation des événements), vous pouvez également utiliser Subscribe
.
okButton . OnClickAsAsyncEnumerable ( ) . Where ( ( x , i ) => i % 2 == 0 ) . Subscribe ( _ =>
{
} ) ;
Async Linq est activé lors de using Cysharp.Threading.Tasks.Linq;
et UniTaskAsyncEnumerable
est défini dans UniTask.Linq
asmdef.
Il est plus proche de l'UNIRX (extensions réactives), mais unitaskasyncenumable est un flux asynchrone basé sur la traction, tandis que Rx était un flux asynchrone basé sur la poussée. Notez que bien que similaires, les caractéristiques sont différentes et les détails se comportent différemment avec eux.
UniTaskAsyncEnumerable
est le point d'entrée comme Enumerable
. En plus des opérateurs de requête standard, il existe d'autres générateurs pour l'unité tels que EveryUpdate
, Timer
, TimerFrame
, Interval
, IntervalFrame
et EveryValueChanged
. Et a également ajouté des opérateurs de requête originaux d'unitask supplémentaires comme Append
, Prepend
, DistinctUntilChanged
, ToHashSet
, Buffer
, CombineLatest
, Merge
Do
, Never
, ForEachAsync
, Pairwise
, Publish
, Queue
, Return
, SkipUntil
, TakeUntil
, SkipUntilCanceled
, TakeUntilCanceled
, TakeLast
, Subscribe
.
La méthode avec FUNC en tant qu'argument a trois surcharges supplémentaires, ***Await
, ***AwaitWithCancellation
.
Select ( Func < T , TR > selector )
SelectAwait ( Func < T , UniTask < TR > > selector )
SelectAwaitWithCancellation ( Func < T , CancellationToken , UniTask < TR > > selector )
Si vous souhaitez utiliser la méthode async
à l'intérieur du func, utilisez le ***Await
ou ***AwaitWithCancellation
.
Comment créer un itérateur asynchronisé: C # 8.0 prend en charge Async Iterator ( async yield return
) mais il permet uniquement IAsyncEnumerable<T>
et bien sûr nécessite C # 8.0. Unitask prend en charge 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 ( ) ;
}
} ) ;
}
Tous les composants UGUI implémentent ***AsAsyncEnumerable
pour convertir des flux asynchrones d'événements.
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. " ) ;
}
Tous les événements de message monobehaviour peuvent convertir les flux asynchronisés par AsyncTriggers
qui peuvent être activés en using Cysharp.Threading.Tasks.Triggers;
. AsyncTrigger peut être créé à l'aide de GetAsync***Trigger
et se déclenche comme unitaskasyncenumable.
var trigger = this . GetOnCollisionEnterAsyncHandler ( ) ;
await trigger . OnCollisionEnterAsync ( ) ;
await trigger . OnCollisionEnterAsync ( ) ;
await trigger . OnCollisionEnterAsync ( ) ;
// every moves.
await this . GetAsyncMoveTrigger ( ) . ForEachAsync ( axisEventData =>
{
} ) ;
AsyncReactiveProperty
, AsyncReadOnlyReactiveProperty
est la version d'Unitask de ReactiveProperty. Méthode d'extension BindTo
de IUniTaskAsyncEnumerable<T>
pour la liaison des valeurs de flux asynchrones vers les composants d'unité (texte / selectable / tmp / texte).
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 ) ;
Un flux asynchrone de type pull n'obtient pas les valeurs suivantes tant que le traitement asynchrone dans la séquence n'est terminé. Cela pourrait renverser les données des événements de type push tels que des boutons.
// can not get click event during 3 seconds complete.
await button . OnClickAsAsyncEnumerable ( ) . ForEachAwaitAsync ( async x =>
{
await UniTask . Delay ( TimeSpan . FromSeconds ( 3 ) ) ;
} ) ;
Il est utile (éviter le double-cliquez) mais pas utile parfois.
L'utilisation de la méthode Queue()
sera également des événements de file d'attente pendant le traitement asynchrone.
// queued message in asynchronous processing
await button . OnClickAsAsyncEnumerable ( ) . Queue ( ) . ForEachAwaitAsync ( async x =>
{
await UniTask . Delay ( TimeSpan . FromSeconds ( 3 ) ) ;
} ) ;
Ou utilisez le style Subscribe
, incendier et oublier.
button . OnClickAsAsyncEnumerable ( ) . Subscribe ( async x =>
{
await UniTask . Delay ( TimeSpan . FromSeconds ( 3 ) ) ;
} ) ;
Channel
est le même que System.threading.tasks.channels qui est similaire à un canal Golang.
Actuellement, il ne prend en charge que les canaux non liés à un producteur multiple. Il peut créer par Channel.CreateSingleConsumerUnbounded<T>()
.
Pour le producteur ( .Writer
), utilisez TryWrite
pour pousser la valeur et TryComplete
pour terminer la chaîne. Pour Consumer ( .Reader
), utilisez TryRead
, WaitToReadAsync
, ReadAsync
, Completion
et ReadAllAsync
pour lire les messages en file d'attente.
ReadAllAsync
renvoie IUniTaskAsyncEnumerable<T>
SO requête les opérateurs LINQ. Lecteur permet uniquement à un seul consommateur mais utilise l'opérateur de requête .Publish()
pour activer le message de multidiffusion. Par exemple, faites du pub / sous-utilitaire.
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 présente le type attendable, attendable. Pour le dire simplement, vous êtes attendu peut être considéré comme un sous-ensemble d'Unitask, et en fait, la conception de l'attente a été influencée par Unitask. Il devrait être en mesure de gérer les attentes basées sur Playerloop, les tâches regroupées et la prise en charge de l'annulation avec CancellationToken
de la même manière. Avec son inclusion dans la bibliothèque standard, vous pouvez vous demander de continuer à utiliser Unitask ou à migrer vers un attente. Voici un bref guide.
Premièrement, les fonctionnalités fournies par Awaitable équivaut à ce que les Coroutines offrent. Au lieu de yield return
, vous utilisez AWAIT; await NextFrameAsync()
remplace yield return null
; Et il y a des équivalents pour WaitForSeconds
et EndOfFrame
. Cependant, c'est l'étendue. Étant basé sur la coroutine en termes de fonctionnalités, il manque de fonctionnalités basées sur les tâches. Dans le développement des applications pratiques à l'aide d'Async / Await, des opérations comme WhenAll
sont essentielles. De plus, Unitask permet de nombreuses opérations basées sur des trames (telles que DelayFrame
) et un contrôle plus flexible PlayerLooptiming, qui ne sont pas disponibles en attente. Bien sûr, il n'y a pas non plus de fenêtre de tracker.
Par conséquent, je recommande d'utiliser Unitask pour le développement des applications. Unitask est un superset de l'attente et comprend de nombreuses caractéristiques essentielles. Pour le développement de la bibliothèque, où vous souhaitez éviter les dépendances externes, l'utilisation attendable comme type de retour pour les méthodes serait appropriée. L'attente peut être convertie en Unitask à l'aide AsUniTask
, il n'y a donc aucun problème à gérer les fonctionnalités attendables dans la bibliothèque unitank. Bien sûr, si vous n'avez pas besoin de vous soucier des dépendances, l'utilisation de Unitask serait le meilleur choix même pour le développement de la bibliothèque.
L'attribut d'Unity [UnityTest]
peut tester la coroutine (ienumerator) mais ne peut pas tester l'async. UniTask.ToCoroutine
Bridges Async / Await à Coroutine afin que vous puissiez tester les méthodes asynchrones.
[ 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 ;
}
} ) ;
Les propres tests unitaires d'Unitask sont écrits à l'aide d'un Unity Test Runner et Cysharp / RunTimeUnitStToolkit pour intégrer avec CI et vérifier si IL2CPP fonctionne.
La plupart des méthodes Unitask s'exécutent sur un seul thread (PlayerLoop), avec uniquement UniTask.Run
( Task.Run
équivalent) et UniTask.SwitchToThreadPool
fonctionnant sur un pool de threads. Si vous utilisez un pool de fils, cela ne fonctionnera pas avec WebGL et ainsi de suite.
UniTask.Run
est désormais obsolète. Vous pouvez plutôt utiliser UniTask.RunOnThreadPool
. Et déterminez également si vous pouvez utiliser UniTask.Create
ou UniTask.Void
.
Vous pouvez convertir la coroutine (ienumerator) en unitask (ou attendre directement) mais il a quelques limites.
WaitForEndOfFrame
/ WaitForFixedUpdate
/ Coroutine
n'est pas pris en charge.StartCoroutine
, il utilise le joueur spécifié PlayerLoopTiming
et le PlayerLoopTiming.Update
par défaut.Update est exécuté avant Update
de Monobehaviour et la boucle de StartCoroutine
. Si vous voulez une conversion entièrement compatible de Coroutine en asynchronisation, utilisez la surcharge IEnumerator.ToUniTask(MonoBehaviour coroutineRunner)
. Il exécute StartCoroutine sur une instance de l'argument monobehaviour et attend qu'il se termine dans unitask.
Unitask peut fonctionner sur Unity Editor comme un éditeur Coroutine. Cependant, il y a certaines limites.
DelayType.Realtime
qui attend le bon moment.EditorApplication.update
.-batchmode
avec -quit
ne fonctionne pas car Unity n'exécute pas EditorApplication.update
et quitte après une seule trame. Au lieu de cela, n'utilisez pas -quit
et quittez manuellement avec EditorApplication.Exit(0)
. Unitask a de nombreuses API standard de type tâche. Ce tableau montre quelles sont les API alternatives.
Utilisez le type standard.
Type .NET | Type d'unité |
---|---|
IProgress<T> | --- |
CancellationToken | --- |
CancellationTokenSource | --- |
Utilisez un type de cycle d'unité.
Type .NET | Type d'unité |
---|---|
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 cache agressivement les objets Async Promise pour atteindre une allocation zéro (pour les détails techniques, voir le blog Unitask V2 - Allocation zéro asynchrone / AWAIT for Unity, avec linq asynchrone). Par défaut, il cache toutes les promesses, mais vous pouvez configurer TaskPool.SetMaxPoolSize
à votre valeur, la valeur indique la taille du cache par type. TaskPool.GetCacheSizeInfo
renvoie actuellement des objets mis en cache dans le pool.
foreach ( var ( type , size ) in TaskPool . GetCacheSizeInfo ( ) )
{
Debug . Log ( type + " : " + size ) ;
}
Dans UnityEditor, le profileur montre l'allocation de l'asyncstatemachine générée par le compilateur, mais elle ne se produit que dans la construction de débogage (développement). C # Compiler génère AsyncstateMachine en tant que classe sur la construction de débogage et en tant que structure sur la construction de version.
Unity prend en charge l'option d'optimisation du code à partir de 2020.1 (droite, pied de page).
Vous pouvez modifier l'optimisation du compilateur C # pour éliminer l'allocation asyncstatemachine dans les versions de développement. Cette option d'optimisation peut également être définie via Compilation.CompilationPipeline-codeOptimization
et Compilation.CodeOptimization
.
La synchronisation par défaut d'Unity ( UnitySynchronizationContext
) est une mauvaise implémentation pour les performances. Unitask contourne SynchronizationContext
(et ExecutionContext
) afin qu'il ne l'utilise pas mais s'il existe dans async Task
, l'a toujours utilisé. UniTaskSynchronizationContext
est un remplacement de UnitySynchronizationContext
qui est mieux pour les performances.
public class SyncContextInjecter
{
[ RuntimeInitializeOnLoadMethod ( RuntimeInitializeLoadType . SubsystemRegistration ) ]
public static void Inject ( )
{
SynchronizationContext . SetSynchronizationContext ( new UniTaskSynchronizationContext ( ) ) ;
}
}
Il s'agit d'un choix facultatif et n'est pas toujours recommandé; UniTaskSynchronizationContext
est moins performant que async UniTask
et n'est pas un remplacement complet de l'unité. Il ne garantit pas non plus la compatibilité comportementale complète avec le UnitySynchronizationContext
.
Les références API d'Unitask sont hébergées sur cysharp.github.io/unitask par docfx et cysharp / docfxtemplate.
Par exemple, les méthodes d'usine d'Unitask peuvent être vues sur les méthodes Unitask #. Les méthodes d'usine / d'extension de UnitaskasynCenumerable peuvent être vues sur Unitaskasyncenumerable # Méthodes.
Nécessite une version d'unité qui prend en charge le paramètre de requête du chemin pour les packages GIT (Unity> = 2019.3.4f1, Unity> = 2020.1A21). Vous pouvez ajouter https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask
au gestionnaire de packages
ou ajoutez "com.cysharp.unitask": "https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask"
à Packages/manifest.json
.
Si vous souhaitez définir une version cible, Unitask utilise la *.*.*
Release afin que vous puissiez spécifier une version comme #2.1.0
. Par exemple, https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask#2.1.0
.
Pour .NET Core, utilisez NuGet.
PM> UNITAGE INSTALLATION
Unitask of .NET Core Version est un sous-ensemble d'unité Unitask avec les méthodes dépendantes de PlayerLoop supprimées.
Il s'exécute à des performances plus élevées que la tâche standard / Valutask, mais vous devez faire attention à ignorer le ExécutionContext / SynchronisationContext lorsque vous l'utilisez. AsyncLocal
ne fonctionne pas non plus car il ignore ExecutionContext.
Si vous utilisez Unitask en interne, mais fournissez Valutask en tant qu'API externe, vous pouvez l'écrire comme ce qui suit (inspiré de PoolledAwait).
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 Version est destiné à permettre aux utilisateurs d'utiliser Unitask comme interface lors du partage du code avec Unity (comme Cysharp / Magiconion). .NET La version Core de Unitask permet le partage de code lisse.
Des méthodes d'utilité telles que lorsque tous les éléments qui équivaut à unitask sont fournis sous forme de cysharp / valluetasksupplement.
Cette bibliothèque est sous la licence MIT.