Comment Task.Yield
travail sous le capot en Mono/WASM d'exécution (qui est utilisé par Blazor WebAssembly)?
Pour être clair, je crois que j'ai une bonne compréhension de la façon dont Task.Yield
travaux dans .NET Framework et .NET de Base. Mono mise en œuvre n'a pas l'air très différent, en un mot, il revient à ceci:
static Task Yield()
{
var tcs = new TaskCompletionSource<bool>();
System.Threading.ThreadPool.QueueUserWorkItem(_ => tcs.TrySetResult(true));
return tcs.Task;
}
Étonnamment, cela fonctionne en Blazor WebAssembly, trop (essayer en ligne):
<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();
}
}
}
Naturellement, tout cela se passe sur la même boucle d'événement de fil dans le navigateur, alors je me demande comment il fonctionne sur le niveau inférieur.
Je soupçonne, il pourrait être en utilisant quelque chose comme Emscripten de Asyncify, mais finalement, faut-il utiliser une sorte de Plate-forme Web API pour planifier une poursuite de rappel? Et si c'est le cas, exactement (comme queueMicrotask
, setTimout
, Promise.resove().then
, etc)?
Mise à jour, je viens de découvrir que l' Thread.Sleep
est mis en œuvre et il en fait des blocs de la boucle d'événement de fil
setTimeout
pourriez-vous expliquer un écart énorme, j'en vois lors de la synchronisation d'une boucle deawait new Promise(r => setTimeout(r, 0))
avec JS interop vs une boucle deawait Task.Yield
? Est-il une faille dans le test? blazorrepl.telerik.com/QlFFQLPF08dkYRbm30