Cum Task.Yield
munca sub capota in Mono/WASM de execuție (care este utilizat de către Blazor WebAssembly)?
Pentru a clarifica, cred că am o bună înțelegere a cum Task.Yield
funcționează în .NET Framework și .NET Core. Mono aplicare nu arata cu mult diferit, într-un cuvânt, totul se rezumă la asta:
static Task Yield()
{
var tcs = new TaskCompletionSource<bool>();
System.Threading.ThreadPool.QueueUserWorkItem(_ => tcs.TrySetResult(true));
return tcs.Task;
}
În mod surprinzător, acest lucru funcționează în Blazor WebAssembly, prea (încercați să-l on-line):
<label>Tick Count: @tickCount</label><br>
@code
{
int tickCount = System.Environment.TickCount;
protected override void OnAfterRender(bool firstRender)
{
if (firstRender) CountAsync();
}
static Task Yield()
{
var tcs = new TaskCompletionSource<bool>();
System.Threading.ThreadPool.QueueUserWorkItem(_ => tcs.TrySetResult(true));
return tcs.Task;
}
async void CountAsync()
{
for (var i = 0; i < 10000; i++)
{
await Yield();
tickCount = System.Environment.TickCount;
StateHasChanged();
}
}
}
Desigur, totul se întâmplă pe același eveniment buclă de fir în browser-ul, așa că am întreb cum funcționează la nivelul inferior.
Eu bănuiesc că ar putea fi folosind ceva de genul Emscripten e Asyncify, dar în cele din urmă, se folosesc un fel de Platforma Web API pentru a programa o continuare callback? Și dacă da, care anume (cum ar fi queueMicrotask
, setTimout
, Promise.resove().then
, etc)?
Actualizat, am descoperit că Thread.Sleep
este implementat, precum și, de fapt, blocuri de bucla eveniment fir
setTimeout
, ați putea explica o mare discrepanță văd atunci când momentul o buclă deawait new Promise(r => setTimeout(r, 0))
cu JS interop vs o buclă deawait Task.Yield
? Există un defect în test? blazorrepl.telerik.com/QlFFQLPF08dkYRbm30