Como funciona Task.Yield
trabalho sob o capô em Mono/WASM de tempo de execução (que é usado pelo Blazor WebAssembly)?
Para esclarecer, eu acredito que eu tenha um bom entendimento de como Task.Yield
funciona em .NET Framework e .NET Núcleo. Mono implementação não parece muito diferente, em poucas palavras, tudo se resume a isto:
static Task Yield()
{
var tcs = new TaskCompletionSource<bool>();
System.Threading.ThreadPool.QueueUserWorkItem(_ => tcs.TrySetResult(true));
return tcs.Task;
}
Surpreendentemente, isso funciona em Blazor WebAssembly, também (experimentá-lo 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();
}
}
}
Naturalmente, tudo acontece no mesmo ciclo de eventos thread no navegador, então eu me pergunto como ele funciona no nível inferior.
Eu suspeito, ele pode ser utilizando algo como Emscripten do Asyncify, mas, eventualmente, faz uso de algum tipo de Plataforma Web API para agendar uma continuação chamada de retorno? E se sim, qual exatamente (como queueMicrotask
, setTimout
, Promise.resove().then
, etc)?
Atualizado, eu apenas descobri que Thread.Sleep
é implementado como bem e ele realmente bloqueia o ciclo de eventos thread
setTimeout
, você poderia explicar um enorme discrepância eu estou a ver, quando o tempo de um ciclo deawait new Promise(r => setTimeout(r, 0))
a galeria de interoperabilidade vs um ciclo deawait Task.Yield
? Existe uma falha no teste? blazorrepl.telerik.com/QlFFQLPF08dkYRbm30