Ako sa Úlohy.Výnos práce pod kapotou v Blazor WebAssembly?

0

Otázka

Ako funguje Task.Yield práce pod kapotou v Mono/WASM runtime (ktorý používa Blazor WebAssembly)?

Na objasnenie, verím, že majú dobré znalosti o tom, ako Task.Yield pracuje v .NET Framework a .NET Core. Mono vykonávanie nevyzerá veľmi odlišná, v skratke, príde na to:

static Task Yield() 
{
    var tcs = new TaskCompletionSource<bool>();
    System.Threading.ThreadPool.QueueUserWorkItem(_ => tcs.TrySetResult(true));
    return tcs.Task;
}

Prekvapivo to funguje v Blazor WebAssembly, príliš (skúste si to 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();
        }
    }
}

Prirodzene, to všetko sa deje na tú istú udalosť slučky niť v prehliadači, takže som zvedavý, ako to funguje na nižšej úrovni.

Mám podozrenie, že by mohlo byť využitie niečo ako Emscripten je Asyncify, ale nakoniec sa to použiť nejakú Webovú Platformu API naplánovať pokračovanie spätný hovor? A ak áno, ktoré presne jeden (ako queueMicrotask, setTimout, Promise.resove().thenatď.)?


Aktualizovaná, práve som zistil, že Thread.Sleep je implementovaný ako dobre a je to vlastne blokuje prípade slučky niť

.net async-await blazor c#
2021-11-24 06:13:47
1

Najlepšiu odpoveď

5

Je to setTimeout. Existuje značná dereference medzi týmto a QueueUserWorkItem,, ale to je miesto, kde to dna von.

Väčšina WebAssembly-konkrétne stroje môže byť videný v PR 38029. Na WebAssembly vykonávanie RequestWorkerThread hovory súkromné metóda s názvom QueueCallback, ktorý je implementovaný v C kód mono_wasm_queue_tp_cb. To vyvolá v mono_threads_schedule_background_job, ktorá zase hovory schedule_background_exec, ktorá je implementovaná v Strojom ako:

export function schedule_background_exec(): void {
    ++pump_count;
    if (typeof globalThis.setTimeout === "function") {
        globalThis.setTimeout(pump_message, 0);
    }
}

Na setTimeout žiadosť o spätný hovor nakoniec dosiahne ThreadPool.Callback, ktorá vyvolá ThreadPoolWorkQueue.Dispatch.

Zvyšok nie je špecifické pre Blazor vôbec, a možno študovať čítaním zdrojový kód ThreadPoolWorkQueue triedy. V skratke, ThreadPool.QueueUserWorkItem enqueues spätných v ThreadPoolQueue. Enqueueing hovory EnsureThreadRequested, ktoré delegátov RequestWorkerThread, implementovaný ako je opísané vyššie. ThreadPoolWorkQueue.Dispatch spôsobuje určitý počet asynchrónne úlohy, aby sa z frontu vyradený a vykonaný; medzi nimi, spätné volanie odovzdané QueueUserWorkItem by nakoniec objaví.

2021-11-28 11:17:30

Veľký odpoveď, tks! Ale je to geven setTimeout, mohli by ste vysvetliť, obrovský rozpor som videl, keď načasovanie a slučka await new Promise(r => setTimeout(r, 0)) s JS interop vs slučka await Task.Yield? Je tam chyba v teste? blazorrepl.telerik.com/QlFFQLPF08dkYRbm30
noseratio

queueMicrotask (na rozdiel od setTimeout) produkuje oveľa bližšie výsledok: blazorrepl.telerik.com/QFbFGVFP10NWGSam57
noseratio

Nie som schopný otvoriť niektorú z ZVE odkazy, takže nemôžem povedať, čo máte na mysli. Ale ak študujete zdrojový kód ThreadPoolWorkQueue.Dispatch, všimnete si, že je nejaký sofistikovaný plánovanie zapojený aj jeden setTimeout môže slúžiť viac v poradí .ČISTÝ asynchrónne úlohy, ktoré by som očakávať, že sa rýchlejšie, než mať každý setTimeout odoslanie jednej spät. hovor.
user3840170

Odd zve odkazy nefungujú. Ak by ste stále chceli to skúsiť, tu je podstata: gist.github.com/noseratio/73f6cd2fb328387ace2a7761f0b0dadc. Je to literrally 8000ms vs 20ms. Potom stačí vymeniť setTimeout s queueMicrotaska je to o rovnaké 20ms.
noseratio

Vyzerá to, že: setTimeout robí proces prehliadača prípade slučky medzi volania, ale .ČISTÝ runtime môže odoslania viacerých asynchrónnych úloh v jednom setTimeout žiadosť o spätný hovor (dequeuing ich takmer okamžite po ich poradí), čím sa zabráni réžiu dávajúce prípade slučky. (Tiež, prehliadače môžu vykonávať škrtiace na setTimeout hovory, ktoré sa táto dávkovacia vyhýba.) Toto bude účinkovať približne rovnaké queueMicrotask. Hoci časovanie sa dostanete, sú pravdepodobne nie je veľmi presné, vďaka Spectre mitigations.
user3840170

V iných jazykoch

Táto stránka je v iných jazykoch

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................