【问题标题】:Blazor UI freeze even when Task is used即使使用 Task,Blazor UI 也会冻结
【发布时间】:2020-05-18 07:16:13
【问题描述】:

考虑 Blazor WebAssembly 应用程序(ASP.NET Core 托管)“空”项目。我将 Counter 页面调整如下:

<button class="btn btn-primary" @onclick="IncrementCountAsync">Click me</button>

及其 Counter.razor.cs 文件:

public partial class Counter
{
    private static int currentCount = 0;

    private async Task IncrementCountAsync()
    {
        Console.WriteLine("Increment called");

        _ = HeavyComputeAsync();

        currentCount++;

        Console.WriteLine($"Counter = {currentCount}");
    }

    private static Task<int> HeavyComputeAsync()
    {
        return Task.Run(() =>
        {
            Console.WriteLine("Task start");

            for (long ndx = 0; ndx < 1000000; ++ndx)
                ndx.ToString();

            Console.WriteLine("Task end");
            return 0;
        });
    }
}

我将 HeavyComputeAsync 方法称为 _ = ...,它不应该等到 IncrementCountAsync 方法完成,而是立即更新currentCount

当我运行应用程序时,我可以在控制台中看到预期的行为:

Increment called
Counter = 1
Task start
Task end (after a while)

尽管 UI 冻结,但它不会更新计数器。确切地说,有时它会立即更新:-O,但大多数时候计数器仅在任务完成后更新。

我希望任务并行运行(在另一个线程中)并且不应该阻塞 UI。

我知道 IncrementCountAsync 在这种情况下会同步运行,因为我正在调用 _ = HeavyComputeAsync。我尝试用 await = ... 调用它,但即使在这种情况下 UI 被冻结,我也无法单击其他页面。

如何实现UI即时更新?

谢谢,Csaba :-)

【问题讨论】:

  • 您尝试改用new TaskFactory().StartNew 吗?或Task.Delay(1).ContinueWith

标签: c# asp.net-core task blazor


【解决方案1】:

在 Blazor WebAssembly 中,您只有 1 个线程。那是(当前)浏览器 / JavaScript 限制,也适用于所有 Wasm 应用程序。

所以 Task.Run() 不能像在服务器上那样工作。代码必须在主线程上执行。

任何“繁重的操作”都会阻塞 UI,这是预期的行为。

您在这里唯一可以做的就是将其分解为多个较小的步骤并运行带有或不带有 Task.Run() 的那些,可以使 UI 在它们之间的间隙中更新。

我已经用示例代码here发布了相关答案

【讨论】:

  • 我完全同意,但如果我们将StateHasChange() 放入任务中,它应该相应地更新视图
  • 仅当您释放线程一段时间 - 参见例如stackoverflow.com/a/60584976/60761
  • 这很可悲 :-(,希望尽快解决。感谢您的帮助 :-)
  • Blazor 无法改变这一点,我们必须等待下一次 JS 和 Wasm 更新。
  • 我想我在某个地方看到 Chrome 中的 wasm 人员正在研究实际的多任务(多线程),所以也许我们会在 Blazor 中免费获得它
【解决方案2】:

你的班级应该和下面的一样。意识到 Blazor WebAssembly 在 JavaScript 运行的同一线程下运行;也就是说,单个 UI 线程。所以在这里使用 Task.Run 是行不通的。像我在这里一样使用 Task.Delay,并验证 Blazor 的异步功能是否有效。是的,它确实。在这种情况下,您还应该意识到,当两个或多个线程并行运行时,异步不是并行编程。

public partial class Counter
{
    private static int currentCount = 0;

    private async Task IncrementCountAsync()
    {
        Console.WriteLine("Increment called");

        currentCount++;



        await Task.Delay(5000);

        Console.WriteLine($"Counter = {currentCount}");


    }

}

此处的代码仅用于演示目的,但如果您想执行长时间运行的操作,您可以使用this sample code

【讨论】:

    猜你喜欢
    • 2018-04-28
    • 2011-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多