Jak to Task.Yield
praca pod maską w środowisku wykonywania Mono/WASM (który jest używany w sieci web montażem Blazor)?
Aby wyjaśnić, uważam, że dobrze wiem, jak Task.Yield
działa w .NET Framework .NET Core. Realizacja Mono nie różni się, w skrócie, wszystko sprowadza się do następującego:
static Task Yield()
{
var tcs = new TaskCompletionSource<bool>();
System.Threading.ThreadPool.QueueUserWorkItem(_ => tcs.TrySetResult(true));
return tcs.Task;
}
Zaskakujące, ale to działa i w sieci web złożeniu Blazor (spróbuj online).:
<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();
}
}
}
Naturalnie, wszystko to dzieje się w jednym i tym samym wątku cyklu wydarzeń w przeglądarce, więc zastanawiam się, jak to działa na niższym poziomie.
Podejrzewam, że może użyć coś takiego Asyncify Emscripten, ale w końcu, czy używa jakiegoś API platformy internetowej dla planowania oddzwonienia kontynuować? A jeśli tak, to jakie (np.queueMicrotask
, setTimout
, Promise.resove().then
itp.)?
Aktualizacja, właśnie odkryłem, że Thread.Sleep
realizowany jest również, i to faktycznie blokuje przepływ cyklu wydarzeń
setTimeout
czy mógłby pan wyjaśnić ogromna rozbieżność, którą widzę po wybraniu czasu cykluawait new Promise(r => setTimeout(r, 0))
z interakcją JS przeciwko cykluawait Task.Yield
? Czy jest jakiś błąd w teście? blazorrepl.telerik.com/QlFFQLPF08dkYRbm30