Görev nasıl yapılır.Blazor Webassembly'da kaputun altında verim çalışması mı?

0

Soru

Nasıl yapar Task.Yield Mono / WASM çalışma zamanında kaputun altında çalışın (Blazor WebAssembly tarafından kullanılır)?

Netleştirmek için, ben inanıyorum ki iyi bir anlayış nasıl Task.Yield çalışmalar içinde .NET Çerçeve ve .NET Çekirdek. Mono uygulama çok farklı görünmüyor, özetle, buna geliyor:

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

Şaşırtıcı bir şekilde, bu Blazor Webassembly'da da çalışır (çevrimiçi deneyin).:

<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();
        }
    }
}

Doğal olarak, hepsi tarayıcıda aynı olay döngüsü iş parçacığında gerçekleşir, bu yüzden alt düzeyde nasıl çalıştığını merak ediyorum.

Emscripten'in Asyncify gibi bir şey kullanıyor olabileceğinden şüpheleniyorum, ancak sonunda devam eden bir geri arama planlamak için bir çeşit Web Platformu API'sı kullanıyor mu? Ve eğer öyleyse, tam olarak hangisi (örneğinqueueMicrotask, setTimout, Promise.resove().then, vb.)?


Güncellendi, bunu yeni keşfettim Thread.Sleep bu da uygulanır ve aslında olay döngüsü iş parçacığını engeller

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

En iyi cevabı

5

Onun setTimeout. Bununla arasında kayda değer bir yönelim var. QueueUserWorkItem ama dibe vurduğu yer burası.

Webassembly'a özgü makinelerin çoğu PR 38029'da görülebilir. WebAssembly uygulaması RequestWorkerThread adlı özel bir yöntemi çağırır QueueCallback, c kodunda şu şekilde uygulanır: mono_wasm_queue_tp_cb. Bu in çağırırmono_threads_schedule_background_job sırayla çağıran schedule_background_exec, typescript'te şu şekilde uygulanır::

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

Bu setTimeout geri arama sonunda ulaşır ThreadPool.Callback, hangi çağırır ThreadPoolWorkQueue.Dispatch.

Geri kalanı Blazor'a özgü değildir ve Blazor'un kaynak kodunu okuyarak incelenebilir.ThreadPoolWorkQueue sınıf. Kısaca, ThreadPool.QueueUserWorkItem bir geri arama enqueues ThreadPoolQueue. Enqueueing çağrıları EnsureThreadRequested. hangi delegelere RequestWorkerThread, yukarıdaki gibi uygulanır. ThreadPoolWorkQueue.Dispatch bazı zaman uyumsuz görevler dequeued ve yürütülmesine neden olur; Bunlar arasında, geri arama için geçirilen QueueUserWorkItem sonunda ortaya çıkmalı.

2021-11-28 11:17:30

Harika bir cevap, tks! Ama geven öyle setTimeout, bir döngüyü zamanlarken gördüğüm büyük bir tutarsızlığı açıklayabilir misiniz await new Promise(r => setTimeout(r, 0)) JS ınterop vs bir döngü ile await Task.Yield? Testte bir kusur mu var? blazorrepl.telerik.com/QlFFQLPF08dkYRbm30
noseratio

queueMicrotask (a karşı setTimeout) çok daha yakın bir sonuç üretir: blazorrepl.telerik.com/QFbFGVFP10NWGSam57
noseratio

REPL bağlantılarından hiçbirini açamıyorum, bu yüzden ne demek istediğinizi anlayamıyorum. Ama eğer kaynak kodunu incelerseniz ThreadPoolWorkQueue.Dispatch göreceksiniz bazı gelişmiş planlama de dahil olduğu ve bir setTimeout her birine sahip olmaktan daha hızlı olmasını beklediğim birden çok sıraya alınmış. NET zaman uyumsuz görevlere hizmet edebilir setTimeout tek bir geri arama gönderin.
user3840170

Tek repl bağlantıları çalışmıyor. Hala denemek istersen, işte özü: gist.github.com/noseratio/73f6cd2fb328387ace2a7761f0b0dadc. Kelimenin tam anlamıyla 8000ms vs 20ms. Sonra sadece değiştirin setTimeout ile queueMicrotask ve yaklaşık aynı 20ms.
noseratio

Öyle görünüyor: setTimeout tarayıcının geri aramalar arasındaki olay döngüsünü işlemesini sağlar, ancak. NET çalışma zamanı birden çok eşzamansız görevi tek bir işlemde gönderebilir setTimeout geri arama (sıraya alındıktan hemen sonra bunları dequeuing), böylece olay döngüsüne verim yükünü önler. (Ayrıca, tarayıcılar üzerinde kısma gerçekleştirebilir setTimeout bu toplu işlemden kaçınan çağrılar.) Bu kabaca eşdeğer bir etki üretir queueMicrotask. Aldığınız zamanlamalar muhtemelen çok doğru olmasa da, Spectre hafifletmeleri sayesinde.
user3840170

Diğer dillerde

Bu sayfa diğer dillerde

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