Memberikan integrasi async/menunggu alokasi yang efisien untuk persatuan.
UniTask<T>
dan asyncmethodbuilder khusus untuk mencapai alokasi nolUniTask.Yield
, UniTask.Delay
, UniTask.DelayFrame
, dll.) Itu memungkinkan penggantian semua operasi coroutine Untuk detail teknis, lihat posting blog: Unitask v2 - nol alokasi async/wait for unity, dengan linq asinkron asinkron
Untuk tips canggih, lihat posting blog: Perluas UnityWebRequest melalui Pola Dekorator Async - Teknik Lanjutan dari Unitask
Instal melalui paket UPM dengan referensi git atau paket aset ( UniTask.*.*.*.unitypackage
) Tersedia di Unitask/Rilis.
// 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 " ) ;
}
Fitur Unitask mengandalkan C# 7.0 (fitur pembangun metode async kustom seperti tugas) sehingga versi Unity yang diperlukan adalah setelah Unity 2018.3
, versi resmi terendah yang didukung adalah Unity 2018.4.13f1
.
Mengapa Unitask (objek seperti tugas khusus) diperlukan? Karena tugas terlalu berat dan tidak cocok dengan Unity Threading (single-thread). Unitask tidak menggunakan utas dan sinkronisasiContext/executionContext karena objek asinkron Unity secara otomatis dikirim oleh lapisan mesin Unity. Ini mencapai alokasi yang lebih cepat dan lebih rendah, dan sepenuhnya terintegrasi dengan persatuan.
Anda dapat menunggu AsyncOperation
, ResourceRequest
, AssetBundleRequest
, AssetBundleCreateRequest
, UnityWebRequestAsyncOperation
, AsyncGPUReadbackRequest
, IEnumerator
dan lainnya saat using Cysharp.Threading.Tasks;
.
Unitask menyediakan tiga pola metode ekstensi.
* await asyncOperation ;
* . WithCancellation ( CancellationToken ) ;
* . ToUniTask ( IProgress , PlayerLoopTiming , CancellationToken ) ;
WithCancellation
adalah versi sederhana dari ToUniTask
, keduanya mengembalikan UniTask
. Untuk detail pembatalan, lihat: Bagian pembatalan dan pengecualian penanganan.
CATATAN: Menunggu secara langsung dikembalikan dari waktu asli PlayerLoop tetapi dengan kankel dan tunitask dikembalikan dari playerlooptiming yang ditentukan. Untuk detail waktu, lihat: Bagian PlayerLoop.
Catatan: AssetBundLeRequest memiliki
asset
danallAssets
, default menungguasset
. Jika Anda ingin mendapatkanallAssets
, Anda dapat menggunakan metodeAwaitForAllAssets()
.
UniTask.WhenEach
UniTask
dapat UniTask.WhenAny
utilitas seperti UniTask.WhenAll
. Mereka seperti Task.WhenAll
Task.WhenAny
Mereka mengembalikan nilai tupel sehingga Anda dapat mendekonstruksi setiap hasil dan melewati banyak jenis.
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 ) ;
}
Jika Anda ingin mengonversi panggilan balik ke Unitask, Anda dapat menggunakan UniTaskCompletionSource<T>
yang merupakan edisi ringan dari 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>
}
Anda dapat mengonversi tugas -> unitask: AsUniTask
, UniTask
-> UniTask<AsyncUnit>
: AsAsyncUnitUniTask
, UniTask<T>
-> UniTask
: AsUniTask
. UniTask<T>
-> Biaya konversi UniTask
gratis.
Jika Anda ingin mengonversi async ke coroutine, Anda dapat menggunakan .ToCoroutine()
, ini berguna jika Anda hanya ingin mengizinkan menggunakan sistem coroutine.
Unitask tidak bisa menunggu dua kali. Ini adalah kendala yang sama dengan Valuetask/Ivaluetasksource yang diperkenalkan dalam .NET Standard 2.1.
Operasi berikut tidak boleh dilakukan pada contoh Valuetask:
- Menunggu instance beberapa kali.
- Memanggil Astask beberapa kali.
- Menggunakan .Result atau .getaWaiter (). GetResult () Ketika operasi belum selesai, atau menggunakannya beberapa kali.
- Menggunakan lebih dari satu teknik ini untuk mengkonsumsi instance.
Jika Anda melakukan salah satu di atas, hasilnya tidak ditentukan.
var task = UniTask . DelayFrame ( 10 ) ;
await task ;
await task ; // NG, throws Exception
Simpan ke bidang kelas, Anda dapat menggunakan UniTask.Lazy
yang mendukung panggilan beberapa kali. .Preserve()
memungkinkan untuk beberapa panggilan (hasil yang di -cache secara internal). Ini berguna ketika ada beberapa panggilan dalam ruang lingkup fungsi.
Juga UniTaskCompletionSource
dapat menunggu beberapa kali dan menunggu dari banyak penelepon.
Beberapa metode pabrik unitask memiliki CancellationToken cancellationToken = default
. Juga beberapa operasi async untuk persatuan memiliki WithCancellation(CancellationToken)
dan ToUniTask(..., CancellationToken cancellation = default)
Metode ekstensi.
Anda dapat meneruskan CancellationToken
ke parameter dengan CancellationTokenSource
standar.
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 dapat dibuat dengan CancellationTokenSource
atau metode ekstensi Monobehaviour GetCancellationTokenOnDestroy
.
// this CancellationToken lifecycle is same as GameObject.
await UniTask . DelayFrame ( 1000 , cancellationToken : this . GetCancellationTokenOnDestroy ( ) ) ;
Untuk pembatalan menyebarkan, semua metode async merekomendasikan untuk menerima CancellationToken cancellationToken
pada argumen terakhir, dan melewati CancellationToken
dari root ke akhir.
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
berarti siklus hidup async. Anda dapat memegang siklus hidup Anda sendiri sebagai gantinya dari CancellationTokenondestroy default.
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 ( ) ;
}
}
Setelah Unity 2022.2, Unity menambahkan CancellationToken di monobehaviour.destroycancellationToken dan application.exitcancellationToken.
Ketika pembatalan terdeteksi, semua metode melempar OperationCanceledException
dan merambat ke hulu. Ketika pengecualian (tidak terbatas pada OperationCanceledException
) tidak ditangani dalam metode async, akhirnya disebarkan ke UniTaskScheduler.UnobservedTaskException
. Perilaku default pengecualian yang tidak ditangani adalah menulis log sebagai pengecualian. Level log dapat diubah menggunakan UniTaskScheduler.UnobservedExceptionWriteLogType
. Jika Anda ingin menggunakan perilaku khusus, atur tindakan ke UniTaskScheduler.UnobservedTaskException.
Dan juga OperationCanceledException
adalah pengecualian khusus, ini diam -diam diabaikan di UnobservedTaskException
.
Jika Anda ingin membatalkan perilaku dalam metode unitask async, lempar OperationCanceledException
secara manual.
public async UniTask < int > FooAsync ( )
{
await UniTask . Yield ( ) ;
throw new OperationCanceledException ( ) ;
}
Jika Anda menangani pengecualian tetapi ingin mengabaikan (menyebarkan ke penanganan pembatalan global), gunakan filter pengecualian.
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 ;
}
}
Lempar/Tangkap OperationCanceledException
sedikit berat, jadi jika kinerjanya menjadi perhatian, gunakan UniTask.SuppressCancellationThrow
untuk menghindari OperationCanceledException Throw. Itu kembali (bool IsCanceled, T Result)
alih -alih melempar.
var ( isCanceled , _ ) = await UniTask . DelayFrame ( 10 , cancellationToken : cts . Token ) . SuppressCancellationThrow ( ) ;
if ( isCanceled )
{
// ...
}
Catatan: Hanya menekan lemparan jika Anda memanggil langsung ke metode sumber terbanyak. Kalau tidak, nilai pengembalian akan dikonversi, tetapi seluruh pipa tidak akan menekan lemparan.
Beberapa fitur yang menggunakan loop pemain Unity, seperti UniTask.Yield
dan UniTask.Delay
dll, menentukan cancellationToken state pada loop pemain. Ini berarti tidak segera membatalkan setelah CancellationToken
dipecat.
Jika Anda ingin mengubah perilaku ini, pembatalan untuk segera, atur bendera cancelImmediately
sebagai argumen.
await UniTask . Yield ( cancellationToken , cancelImmediately : true ) ;
CATATAN: Mengatur cancelImmediately
ke true dan mendeteksi pembatalan langsung lebih mahal daripada perilaku default. Ini karena menggunakan CancellationToken.Register
; Ini lebih berat daripada memeriksa CancellationToken di loop pemain.
Timeout adalah variasi pembatalan. Anda dapat menetapkan batas waktu dengan CancellationTokenSouce.CancelAfterSlim(TimeSpan)
dan melewati CancellationToken ke metode async.
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
adalah API standar. Namun dalam Unity Anda tidak boleh menggunakannya karena tergantung timer threading.CancelAfterSlim
adalah metode ekstensi Unitask, ia menggunakan PlayerLoop sebagai gantinya.
Jika Anda ingin menggunakan batas waktu dengan sumber pembatalan lainnya, gunakan 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. " ) ;
}
}
Optimalkan untuk mengurangi alokasi CancellationTokensource untuk waktu tunggu per panggilan metode async, Anda dapat menggunakan TimeoutController
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 " ) ;
}
}
}
Jika Anda ingin menggunakan batas waktu dengan sumber pembatalan lainnya, gunakan new TimeoutController(CancellationToken)
.
TimeoutController timeoutController ;
CancellationTokenSource clickCancelSource ;
void Start ( )
{
this . clickCancelSource = new CancellationTokenSource ( ) ;
this . timeoutController = new TimeoutController ( clickCancelSource ) ;
}
Catatan: Unitask memiliki .Timeout
, .TimeoutWithoutException
Metode Namun, jika mungkin, jangan gunakan ini, silakan lulus CancellationToken
. Karena .Timeout
kerja dari Eksternal Tugas, tidak dapat menghentikan tugas di luar waktu. .Timeout
berarti mengabaikan hasil saat timeout. Jika Anda melewati CancellationToken
ke metode ini, itu akan bertindak dari dalam tugas, jadi dimungkinkan untuk menghentikan tugas yang sedang berjalan.
Beberapa Operasi Async untuk Unity memiliki metode ekstensi 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 ) ;
Anda tidak boleh menggunakan new System.Progress<T>
, karena itu menyebabkan alokasi setiap saat. Gunakan Cysharp.Threading.Tasks.Progress
sebagai gantinya. Pabrik kemajuan ini memiliki dua metode, Create
dan CreateOnlyValueChanged
. CreateOnlyValueChanged
Calls Hanya ketika nilai kemajuan telah berubah.
Menerapkan antarmuka iprogress ke penelepon lebih baik karena tidak ada alokasi 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 dijalankan di PlayerLoop khusus. Metode Berbasis PlayerLoop Unitask (seperti Delay
, DelayFrame
, asyncOperation.ToUniTask
, dll ...) Terima PlayerLoopTiming
ini.
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
}
Ini menunjukkan kapan harus dijalankan, Anda dapat memeriksa playerlooplist.md ke playerloop default Unity dan loop khusus unitask yang disuntikkan.
PlayerLoopTiming.Update
mirip dengan yield return null
ScriptRunBehaviourUpdate
coroutine ScriptRunDelayedDynamicFrameRate
tetapi dipanggil sebelum pembaruan (pembaruan dan acara uGUI (tombol. PlayerLoopTiming.FixedUpdate
mirip dengan WaitForFixedUpdate
.
PlayerLoopTiming.LastPostLateUpdate
tidak setara denganyield return new WaitForEndOfFrame()
. WaitforendOfframe Coroutine tampaknya berjalan setelah PlayerLoop selesai. Beberapa metode yang membutuhkan akhir bingkai Coroutine (Texture2D.ReadPixels
,ScreenCapture.CaptureScreenshotAsTexture
,CommandBuffer
, dll) tidak berfungsi dengan benar ketika diganti dengan async/menunggu. Dalam kasus ini, lulus monobehaviour (Coroutine Runnner) keUniTask.WaitForEndOfFrame
. Misalnya,await UniTask.WaitForEndOfFrame(this);
alokasi alokasi ringan yang ringan dariyield return new WaitForEndOfFrame()
.Catatan: Dalam Unity 2023.1 atau yang lebih baru,
await UniTask.WaitForEndOfFrame();
tidak lagi membutuhkan monobehaviour. MenggunakanUnityEngine.Awaitable.EndOfFrameAsync
.
yield return null
dan UniTask.Yield
serupa tetapi berbeda. yield return null
Selalu Mengembalikan Frame Berikutnya Tapi UniTask.Yield
Returns Next Disebut. Artinya, call UniTask.Yield(PlayerLoopTiming.Update)
pada PreUpdate
, ia mengembalikan bingkai yang sama. UniTask.NextFrame()
menjamin pengembalian bingkai berikutnya, Anda dapat mengharapkan ini berperilaku persis sama dengan yield return null
.
Unitask.yield (tanpa CancellationToken) adalah tipe khusus, pengembalian
YieldAwaitable
dan dijalankan pada yieldrunner. Ini adalah yang paling ringan dan tercepat.
AsyncOperation
dikembalikan dari waktu asli. Misalnya, menunggu SceneManager.LoadSceneAsync
dikembalikan dari EarlyUpdate.UpdatePreloading
dan setelah dipanggil, Start
adegan yang dimuat dipanggil dari EarlyUpdate.ScriptRunDelayedStartupFrame
. Juga await UnityWebRequest
dikembalikan dari EarlyUpdate.ExecuteMainThreadJobs
.
Di Unitask, menunggu secara langsung menggunakan waktu asli, sementara WithCancellation
dan penggunaan ToUniTask
waktu yang ditentukan. Ini biasanya bukan masalah tertentu, tetapi dengan LoadSceneAsync
, ini menyebabkan urutan awal dan kelanjutan yang berbeda setelah menunggu. Jadi disarankan untuk tidak menggunakan LoadSceneAsync.ToUniTask
.
Catatan: Saat menggunakan Unity 2023.1 atau yang lebih baru, pastikan Anda
using UnityEngine;
Dalam pernyataan menggunakan file Anda saat bekerja denganUnityEngine.Awaitable
yang baru. Metode yang Dapat Ditagih SepertiSceneManager.LoadSceneAsync
. Ini mencegah kesalahan kompilasi dengan menghindari penggunaan VersiUnityEngine.AsyncOperation
.
Di stacktrace, Anda dapat memeriksa di mana ia berjalan di PlayerLoop.
Secara default, PlayerLoop Unitask diinisialisasi di [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
.
Urutan di mana metode dipanggil dalam beforesceneLoad adalah nondeterministik, jadi jika Anda ingin menggunakan unitask dalam metode beforesceneload lainnya, Anda harus mencoba menginisialisasi sebelum ini.
// AfterAssembliesLoaded is called before BeforeSceneLoad
[ RuntimeInitializeOnLoadMethod ( RuntimeInitializeLoadType . AfterAssembliesLoaded ) ]
public static void InitUniTaskLoop ( )
{
var loop = PlayerLoop . GetCurrentPlayerLoop ( ) ;
Cysharp . Threading . Tasks . PlayerLoopHelper . Initialize ( ref loop ) ;
}
Jika Anda mengimpor paket Entities
Unity, itu mengatur ulang loop pemain kustom menjadi default di BeforeSceneLoad
dan menyuntikkan loop ECS. Ketika Unity memanggil metode injeksi ECS setelah metode inisialisasi Unitask, Unitask tidak akan lagi berfungsi.
Untuk menyelesaikan masalah ini, Anda dapat memulai kembali Unitask PlayerLoop setelah ECS diinisialisasi.
// Get ECS Loop.
var playerLoop = ScriptBehaviourUpdateOrder . CurrentPlayerLoop ;
// Setup UniTask's PlayerLoop.
PlayerLoopHelper . Initialize ( ref playerLoop ) ;
Anda dapat mendiagnosis apakah Loop Pemain Unitask siap dengan menelepon PlayerLoopHelper.IsInjectedUniTaskPlayerLoop()
. Dan juga PlayerLoopHelper.DumpCurrentPlayerLoop
mencatat semua pemain saat ini untuk konsol.
void Start ( )
{
UnityEngine . Debug . Log ( " UniTaskPlayerLoop ready? " + PlayerLoopHelper . IsInjectedUniTaskPlayerLoop ( ) ) ;
PlayerLoopHelper . DumpCurrentPlayerLoop ( ) ;
}
Anda dapat mengoptimalkan biaya loop sedikit dengan menghapus injeksi playerlooptiming yang tidak digunakan. Anda dapat menghubungi PlayerLoopHelper.Initialize(InjectPlayerLoopTimings)
di inisialisasi.
var loop = PlayerLoop . GetCurrentPlayerLoop ( ) ;
PlayerLoopHelper . Initialize ( ref loop , InjectPlayerLoopTimings . Minimum ) ; // minimum is Update | FixedUpdate | LastPostLateUpdate
InjectPlayerLoopTimings
memiliki tiga preset, All
dan Standard
(semuanya tanpa terakhir kecuali LastPostLateUpdate), Minimum
( Update | FixedUpdate | LastPostLateUpdate
). Default adalah semua dan Anda dapat menggabungkan waktu suntikan khusus seperti InjectPlayerLoopTimings.Update | InjectPlayerLoopTimings.FixedUpdate | InjectPlayerLoopTimings.PreLateUpdate
.
Anda dapat membuat kesalahan untuk menggunakan PlayerLoopTiming
yang tidak diinyek oleh Microsoft.Codeanalysis.BernedApianAnalizers. Misalnya, Anda dapat mengatur BannedSymbols.txt
seperti ini untuk 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.
Anda dapat mengonfigurasi tingkat keparahan RS0030
untuk kesalahan.
async void
adalah sistem tugas C# standar sehingga tidak berjalan pada sistem unitask. Lebih baik tidak menggunakannya. async UniTaskVoid
adalah versi ringan dari async UniTask
karena tidak ada penyelesaian yang menunggu dan melaporkan kesalahan segera ke UniTaskScheduler.UnobservedTaskException
. Jika Anda tidak memerlukan menunggu (api dan lupa), menggunakan UniTaskVoid
lebih baik. Sayangnya untuk mengabaikan peringatan, Anda harus menelepon Forget()
.
public async UniTaskVoid FireAndForgetMethod ( )
{
// do anything...
await UniTask . Yield ( ) ;
}
public void Caller ( )
{
FireAndForgetMethod ( ) . Forget ( ) ;
}
Juga Unitask memiliki metode Forget
, mirip dengan UniTaskVoid
dan memiliki efek yang sama. Namun UniTaskVoid
lebih efisien jika Anda benar -benar tidak menggunakan await
。
public async UniTask DoAsync ( )
{
// do anything...
await UniTask . Yield ( ) ;
}
public void Caller ( )
{
DoAsync ( ) . Forget ( ) ;
}
Untuk menggunakan async lambda yang terdaftar di suatu acara, jangan gunakan async void
. Sebaliknya, Anda dapat menggunakan UniTask.Action
atau UniTask.UnityAction
, yang keduanya membuat delegasi melalui 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
juga dapat digunakan dalam metode Start
Monobehaviour.
class Sample : MonoBehaviour
{
async UniTaskVoid Start ( )
{
// async init code.
}
}
Berguna untuk memeriksa (bocor) unitk. Anda dapat membuka jendela pelacak di Window -> UniTask Tracker
.
UnitaskTracker dimaksudkan untuk penggunaan debugging hanya karena memungkinkan pelacakan dan menangkap stacktraces berguna tetapi memiliki dampak kinerja yang berat. Penggunaan yang disarankan adalah untuk memungkinkan pelacakan dan stacktraces untuk menemukan kebocoran tugas dan menonaktifkan keduanya saat selesai.
Secara default, Unitask mendukung TextMeshPro ( BindTo(TMP_Text)
dan ekstensi acara TMP_InputField
seperti Standard UGUI InputField
), Dotween ( Tween
as Awaitable) dan Alamat ( AsyncOperationHandle
dan AsyncOperationHandle<T>
Awaitable).
Ada yang didefinisikan dalam ASMDEF terpisah seperti UniTask.TextMeshPro
, UniTask.DOTween
, UniTask.Addressables
.
Dukungan TextMeshPro dan Alamat diaktifkan secara otomatis saat mengimpor paket mereka dari Paket Manager. Namun untuk dukungan dotween, setelah mengimpor dari aset dotween dan menentukan simbol skrip simbol UNITASK_DOTWEEN_SUPPORT
untuk memungkinkannya.
// 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 ) ) ;
Perilaku default Support Dotween ( await
, WithCancellation
, ToUniTask
) menunggu tween terbunuh. Ini bekerja pada baik lengkap (benar/salah) dan membunuh (benar/salah). Tetapi jika Anda ingin menggunakan kembali remaja ( SetAutoKill(false)
), itu tidak berfungsi seperti yang diharapkan. Jika Anda ingin menunggu waktu lain, metode ekstensi berikut ada di Tween, AwaitForComplete
, AwaitForPause
, AwaitForPlay
, AwaitForRewind
, AwaitForStepComplete
.
Unity 2020.2 mendukung C# 8.0 sehingga Anda dapat menggunakan await foreach
. Ini adalah notasi pembaruan baru di era Async.
// Unity 2020.2, C# 8.0
await foreach ( var _ in UniTaskAsyncEnumerable . EveryUpdate ( ) . WithCancellation ( token ) )
{
Debug . Log ( " Update() " + Time . frameCount ) ;
}
Dalam lingkungan C# 7.3, Anda dapat menggunakan metode ForEachAsync
untuk bekerja dengan cara yang hampir sama.
// C# 7.3(Unity 2018.3~)
await UniTaskAsyncEnumerable . EveryUpdate ( ) . ForEachAsync ( _ =>
{
Debug . Log ( " Update() " + Time . frameCount ) ;
} , token ) ;
UniTask.WhenEach
Ketika itu mirip dengan Task.WhenEach
.NET 9. Ketika dapat mengkonsumsi cara baru untuk menunggu banyak tugas.
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 mengimplementasikan linq asinkron, mirip dengan linq di IEnumerable<T>
atau rx di IObservable<T>
. Semua operator kueri LINQ standar dapat diterapkan pada aliran asinkron. Misalnya, kode berikut menunjukkan cara menerapkan filter di mana ke tombol klik tombol asinkron yang berjalan sekali setiap dua klik.
await okButton . OnClickAsAsyncEnumerable ( ) . Where ( ( x , i ) => i % 2 == 0 ) . ForEachAsync ( _ =>
{
} ) ;
Fire and Forget Style (misalnya, penanganan acara), Anda juga dapat menggunakan Subscribe
.
okButton . OnClickAsAsyncEnumerable ( ) . Where ( ( x , i ) => i % 2 == 0 ) . Subscribe ( _ =>
{
} ) ;
Async Linq diaktifkan saat using Cysharp.Threading.Tasks.Linq;
, dan UniTaskAsyncEnumerable
didefinisikan dalam UniTask.Linq
asmdef.
Lebih dekat dengan Unirx (ekstensi reaktif), tetapi unitaskasyncenumerable adalah aliran asinkron berbasis tarikan, sedangkan RX adalah aliran asinkron berbasis push. Perhatikan bahwa meskipun serupa, karakteristiknya berbeda dan detailnya berperilaku berbeda bersama dengan mereka.
UniTaskAsyncEnumerable
adalah titik masuk seperti Enumerable
. Selain operator kueri standar, ada generator lain untuk persatuan seperti EveryUpdate
, Timer
, TimerFrame
, Interval
, IntervalFrame
, dan EveryValueChanged
. Dan juga menambahkan operator kueri asli Unitask tambahan seperti Append
, Prepend
, DistinctUntilChanged
, ToHashSet
, Buffer
, CombineLatest
, Merge
Do
, Never
, ForEachAsync
, Pairwise
, Publish
, Queue
, Return
, SkipUntil
, TakeUntil
, SkipUntilCanceled
, TakeUntilCanceled
, Takelast, Takelast, TakeLast
, Subscribe
.
Metode dengan func sebagai argumen memiliki tiga kelebihan tambahan, ***Await
, ***AwaitWithCancellation
.
Select ( Func < T , TR > selector )
SelectAwait ( Func < T , UniTask < TR > > selector )
SelectAwaitWithCancellation ( Func < T , CancellationToken , UniTask < TR > > selector )
Jika Anda ingin menggunakan metode async
di dalam fungsi, gunakan ***Await
atau ***AwaitWithCancellation
.
Cara Membuat Iterator Async: C# 8.0 Mendukung Async Iterator ( async yield return
) tetapi hanya memungkinkan IAsyncEnumerable<T>
dan tentu saja membutuhkan C# 8.0. Unitask mendukung UniTaskAsyncEnumerable.Create
metode untuk membuat itync iterator khusus.
// 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 ( ) ;
}
} ) ;
}
Semua komponen UGUI mengimplementasikan ***AsAsyncEnumerable
untuk mengonversi aliran peristiwa asinkron.
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. " ) ;
}
Semua peristiwa pesan monobehaviour dapat mengonversi stream async oleh AsyncTriggers
yang dapat diaktifkan dengan using Cysharp.Threading.Tasks.Triggers;
. Asynctrigger dapat dibuat menggunakan GetAsync***Trigger
dan memicu dirinya sebagai unitaskasyncenumerable.
var trigger = this . GetOnCollisionEnterAsyncHandler ( ) ;
await trigger . OnCollisionEnterAsync ( ) ;
await trigger . OnCollisionEnterAsync ( ) ;
await trigger . OnCollisionEnterAsync ( ) ;
// every moves.
await this . GetAsyncMoveTrigger ( ) . ForEachAsync ( axisEventData =>
{
} ) ;
AsyncReactiveProperty
, AsyncReadOnlyReactiveProperty
adalah versi reactiveProperty Unitask. Metode ekstensi BindTo
dari IUniTaskAsyncEnumerable<T>
untuk mengikat nilai aliran asinkron ke komponen Unity (teks/dapat dipilih/tmp/teks).
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 ) ;
Aliran asinkron tipe tarik tidak mendapatkan nilai berikutnya sampai pemrosesan asinkron dalam urutan selesai. Ini dapat menumpahkan data dari peristiwa tipe push seperti tombol.
// can not get click event during 3 seconds complete.
await button . OnClickAsAsyncEnumerable ( ) . ForEachAwaitAsync ( async x =>
{
await UniTask . Delay ( TimeSpan . FromSeconds ( 3 ) ) ;
} ) ;
Ini berguna (mencegah klik dua kali) tetapi kadang-kadang tidak berguna.
Menggunakan metode Queue()
juga akan mengantri selama pemrosesan asinkron.
// queued message in asynchronous processing
await button . OnClickAsAsyncEnumerable ( ) . Queue ( ) . ForEachAwaitAsync ( async x =>
{
await UniTask . Delay ( TimeSpan . FromSeconds ( 3 ) ) ;
} ) ;
Atau gunakan gaya Subscribe
, tembak dan lupakan.
button . OnClickAsAsyncEnumerable ( ) . Subscribe ( async x =>
{
await UniTask . Delay ( TimeSpan . FromSeconds ( 3 ) ) ;
} ) ;
Channel
sama dengan System.threading.tasks.Channels yang mirip dengan saluran Golang.
Saat ini hanya mendukung saluran multi-produser, konsumen tunggal yang tidak memiliki konsumen. Ini dapat membuat dengan Channel.CreateSingleConsumerUnbounded<T>()
.
Untuk produser ( .Writer
), gunakan TryWrite
untuk mendorong nilai dan TryComplete
untuk menyelesaikan saluran. Untuk konsumen ( .Reader
), gunakan TryRead
, WaitToReadAsync
, ReadAsync
, Completion
dan ReadAllAsync
untuk membaca pesan antrian.
ReadAllAsync
mengembalikan IUniTaskAsyncEnumerable<T>
jadi query linq operator. Pembaca hanya memungkinkan konsumen tunggal tetapi menggunakan .Publish()
operator kueri untuk mengaktifkan pesan multicast. Misalnya, buat pub/sub utilitas.
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 memperkenalkan tipe yang menunggu, menunggu. Sederhananya, menunggu dapat dianggap sebagai subset dari unitask, dan pada kenyataannya, desain yang menunggu dapat dipengaruhi oleh unitask. Seharusnya dapat menangani playerloop berbasis menunggu, tugas yang dikumpulkan, dan dukungan untuk pembatalan dengan CancellationToken
dengan cara yang sama. Dengan dimasukkannya dalam pustaka standar, Anda mungkin bertanya -tanya apakah akan terus menggunakan Unitask atau bermigrasi ke menunggu. Ini panduan singkat.
Pertama, fungsionalitas yang disediakan oleh Awaitable setara dengan apa yang ditawarkan Coroutine. Alih -alih yield return
, Anda menggunakan menunggu; await NextFrameAsync()
menggantikan yield return null
; Dan ada setara untuk WaitForSeconds
dan EndOfFrame
. Namun, itulah sejauh mana itu. Menjadi coroutine dalam hal fungsionalitas, ia tidak memiliki fitur berbasis tugas. Dalam pengembangan aplikasi praktis menggunakan async/menunggu, operasi seperti WhenAll
penting. Selain itu, Unitask memungkinkan banyak operasi berbasis bingkai (seperti DelayFrame
) dan kontrol PlayerLooptiming yang lebih fleksibel, yang tidak tersedia dalam menunggu. Tentu saja, juga tidak ada jendela pelacak.
Oleh karena itu, saya sarankan menggunakan Unitask untuk pengembangan aplikasi. Unitask adalah superset yang menunggu dan mencakup banyak fitur penting. Untuk pengembangan perpustakaan, di mana Anda ingin menghindari dependensi eksternal, menggunakan Awaitable sebagai jenis pengembalian untuk metode akan sesuai. Menunggu dapat dikonversi menjadi Unitask menggunakan AsUniTask
, jadi tidak ada masalah dalam menangani fungsionalitas berbasis yang menunggu di dalam perpustakaan Unitask. Tentu saja, jika Anda tidak perlu khawatir tentang dependensi, menggunakan Unitask akan menjadi pilihan terbaik bahkan untuk pengembangan perpustakaan.
Atribut [UnityTest]
Unity dapat menguji coroutine (ienumerator) tetapi tidak dapat menguji async. UniTask.ToCoroutine
menjembatani async/menunggu coroutine sehingga Anda dapat menguji metode async.
[ 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 ;
}
} ) ;
Uji unit Unitask sendiri ditulis menggunakan Unity Test Runner dan Cysharp/RuntimeUntestToolKit untuk berintegrasi dengan CI dan periksa apakah IL2CPP berfungsi.
Sebagian besar metode unitask dijalankan pada satu utas (playerloop), dengan hanya UniTask.Run
( Task.Run
yang setara) dan UniTask.SwitchToThreadPool
berjalan di kumpulan utas. Jika Anda menggunakan kumpulan utas, itu tidak akan berfungsi dengan WebGL dan sebagainya.
UniTask.Run
sekarang sudah usang. Anda dapat menggunakan UniTask.RunOnThreadPool
sebagai gantinya. Dan juga pertimbangkan apakah Anda dapat menggunakan UniTask.Create
atau UniTask.Void
.
Anda dapat mengonversi coroutine (ienumerator) menjadi unitask (atau menunggu secara langsung) tetapi memiliki beberapa keterbatasan.
WaitForEndOfFrame
/ WaitForFixedUpdate
/ Coroutine
tidak didukung.StartCoroutine
, ia menggunakan PlayerLoopTiming
yang ditentukan dan PlayerLoopTiming.Update
default. Update dijalankan sebelum Update
Monobehaviour dan Loop StartCoroutine
. Jika Anda ingin konversi yang sepenuhnya kompatibel dari Coroutine ke Async, gunakan IEnumerator.ToUniTask(MonoBehaviour coroutineRunner)
. Ini mengeksekusi startcoroutine pada contoh argumen monobehaviour dan menunggu untuk diselesaikan di unitask.
Unitask dapat berjalan pada editor Unity seperti editor Coroutine. Namun, ada beberapa keterbatasan.
DelayType.Realtime
yang menunggu waktu yang tepat.EditorApplication.update
timing.-batchmode
dengan -quit
tidak berfungsi karena Unity tidak menjalankan EditorApplication.update
dan berhenti setelah satu frame. Sebaliknya, jangan gunakan -quit
dan berhenti secara manual dengan EditorApplication.Exit(0)
. Unitask memiliki banyak API seperti tugas standar. Tabel ini menunjukkan apa API alternatif.
Gunakan tipe standar.
Jenis .NET | Tipe unitask |
---|---|
IProgress<T> | --- |
CancellationToken | --- |
CancellationTokenSource | --- |
Gunakan tipe unitask.
Jenis .NET | Tipe unitask |
---|---|
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 secara agresif menyimpan objek janji async untuk mencapai alokasi nol (untuk detail teknis, lihat posting blog unitask v2 - nol alokasi async/menunggu untuk persatuan, dengan linq asinkron). Secara default, itu cache semua janji tetapi Anda dapat mengonfigurasi TaskPool.SetMaxPoolSize
ke nilai Anda, nilainya menunjukkan ukuran cache per jenis. TaskPool.GetCacheSizeInfo
Mengembalikan objek yang di -cache saat ini di Pool.
foreach ( var ( type , size ) in TaskPool . GetCacheSizeInfo ( ) )
{
Debug . Log ( type + " : " + size ) ;
}
Di Unityeditor, profiler menunjukkan alokasi kompiler yang dihasilkan asyncstatemachine tetapi hanya terjadi pada debug (pengembangan) build. C# Compiler menghasilkan asyncstatemachine sebagai kelas pada debug build dan sebagai struct pada rilis build.
Unity mendukung opsi optimasi kode mulai dari 2020.1 (kanan, footer).
Anda dapat mengubah optimasi C# Compiler untuk merilis untuk menghapus alokasi asyncstatemachine dalam pembangunan pembangunan. Opsi optimasi ini juga dapat diatur melalui Compilation.CompilationPipeline-codeOptimization
Compilation.CodeOptimization
SynchronizationContext Default Unity ( UnitySynchronizationContext
) adalah implementasi yang buruk untuk kinerja. Unitask bypasses SynchronizationContext
(dan ExecutionContext
) sehingga tidak menggunakannya tetapi jika ada dalam async Task
, masih menggunakannya. UniTaskSynchronizationContext
adalah penggantian UnitySynchronizationContext
yang lebih baik untuk kinerja.
public class SyncContextInjecter
{
[ RuntimeInitializeOnLoadMethod ( RuntimeInitializeLoadType . SubsystemRegistration ) ]
public static void Inject ( )
{
SynchronizationContext . SetSynchronizationContext ( new UniTaskSynchronizationContext ( ) ) ;
}
}
Ini adalah pilihan opsional dan tidak selalu direkomendasikan; UniTaskSynchronizationContext
kurang berkinerja lebih sedikit daripada async UniTask
dan bukan penggantian unitask yang lengkap. Ini juga tidak menjamin kompatibilitas perilaku penuh dengan UnitySynchronizationContext
.
Referensi API Unitask di -host di cysharp.github.io/unitask oleh docfx dan cysharp/docfxtemplate.
Misalnya, metode pabrik Unitask dapat dilihat di metode Unitask#. Metode pabrik/ekstensi unitaskasyncenumerable dapat dilihat di metode unitaskasyncenumerable#.
Membutuhkan versi Unity yang mendukung parameter kueri jalur untuk paket git (Unity> = 2019.3.4f1, Unity> = 2020.1a21). Anda dapat menambahkan https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask
ke manajer paket
Atau tambahkan "com.cysharp.unitask": "https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask"
ke Packages/manifest.json
.
#2.1.0
Anda ingin mengatur versi target, Unitask menggunakan tag rilis *.*.*
Misalnya https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask#2.1.0
.
Untuk .NET Core, gunakan Nuget.
PM> Instal-paket unitask
Unitask dari .NET Core Version adalah subset dari Unity unitask dengan metode dependen playerloop dihapus.
Ini berjalan pada kinerja yang lebih tinggi dari tugas/valueTask standar, tetapi Anda harus berhati -hati untuk mengabaikan ExecutionContext/SynchronizationContext saat menggunakannya. AsyncLocal
juga tidak berfungsi karena mengabaikan ExecutionContext.
Jika Anda menggunakan Unitask secara internal, tetapi berikan ValueTask sebagai API eksternal, Anda dapat menulisnya seperti yang berikut ini (terinspirasi oleh 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..
}
}
Versi inti .NET dimaksudkan untuk memungkinkan pengguna menggunakan Unitask sebagai antarmuka saat berbagi kode dengan Unity (seperti Cysharp/Magiconion). Versi inti NET dari Unitask memungkinkan berbagi kode yang halus.
Metode utilitas seperti ketika semua yang setara dengan unitask disediakan sebagai cysharp/valuetasksupplement.
Perpustakaan ini berada di bawah lisensi MIT.