Jak działa Tusk.Dać pracę pod maską w sieci web złożeniu Blazor?

0

Pytanie

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ń

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

Najlepsza odpowiedź

5

To setTimeout. Istnieje znaczna pośredni związek między tym i QueueUserWorkItemale oto tu wszystko się kończy.

Większość sprzętu dla sieci web montażu można zobaczyć w PR 38029. Realizacja sieci web złożenia RequestWorkerThread powoduje prywatną metodę o nazwie QueueCallback, który jest realizowany w kodzie C jak mono_wasm_queue_tp_cb. To powodujemono_threads_schedule_background_job, co z kolei powodujeschedule_background_exec, który jest realizowany w машинописном postaci jak:

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

To setTimeout oddzwanianie w końcu osiąga ThreadPool.Callback, który powoduje ThreadPoolWorkQueue.Dispatch.

Pozostała jego część w ogóle nie odnosi się do Blazor, i można ją poznać, czytając kod źródłowyThreadPoolWorkQueue klasa. Krótko mówiąc, ThreadPool.QueueUserWorkItem kolejkuje oddzwanianie w ThreadPoolQueue. Połączenia w kolejce EnsureThreadRequested, który deleguje RequestWorkerThread, realizowane w sposób opisany powyżej. ThreadPoolWorkQueue.Dispatch powoduje usunięcie z kolejki i wykonanie pewnej liczby zadań asynchronicznych; wśród nich oddzwanianie, przekazany QueueUserWorkItem w końcu musi się pojawić.

2021-11-28 11:17:30

Doskonała odpowiedź, tks! Ale nawet jeśli to setTimeoutczy mógłby pan wyjaśnić ogromna rozbieżność, którą widzę po wybraniu czasu cyklu await new Promise(r => setTimeout(r, 0)) z interakcją JS przeciwko cyklu await Task.Yield? Czy jest jakiś błąd w teście? blazorrepl.telerik.com/QlFFQLPF08dkYRbm30
noseratio

queueMicrotask (w przeciwieństwie do setTimeout) daje znacznie bardziej zbliżony wynik: blazorrepl.telerik.com/QFbFGVFP10NWGSam57
noseratio

Nie mogę otworzyć żadnego z linków REPL, dlatego nie mogę zrozumieć, co masz na myśli. Ale jeśli zbadać kod źródłowy ThreadPoolWorkQueue.Dispatchmożna zauważyć , że również liczy się trochę skomplikowane planowanie i jeden setTimeout może obsługiwać wiele kolejek .CZYSTE asynchroniczne zadania, które, jak się spodziewał, będą wykonywane szybciej, niż wykonanie każdej setTimeout prześlij jeden oddzwanianie.
user3840170

Dziwne linki repl nie działają. Jeśli nadal chcesz spróbować, to jest istota: gist.github.com/noseratio/73f6cd2fb328387ace2a7761f0b0dadc. To około 8000 ms vs 20 ms. Następnie wystarczy wymienić setTimeout z queueMicrotaski to jest mniej więcej te same 20 ms.
noseratio

Wygląda na to, że to: setTimeout sprawia, że przeglądarka przetwarzać cykl wydarzeń między obciążeniami połączeń, ale .Środowisko sieciowe wykonania może wysyłać kilka asynchronicznych zadań w jednym setTimeout oddzwanianie (usuwanie ich z kolejki niemal natychmiast po tym, jak są one ustawione w kolejności), co pozwala uniknąć kosztów związanych z cyklem wydarzeń. (Ponadto, przeglądarki mogą wykonywać regulacje na setTimeout połączenia, których ta grupa unika.) To daje efekt, około równoważny queueMicrotask. Choć czas, który masz, to chyba nie jest bardzo dokładne, dzięki смягчениям widma.
user3840170

W innych językach

Ta strona jest w innych językach

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