首页 > 解决方案 > Task.Run 然后使用异步等待 ContinueWith 在主线程替代上调用?

问题描述

以下代码完美运行。它在 UI 上显示微调器,使用线程池中的线程启动任务并运行繁重的操作,一旦完成,隐藏微调器的逻辑将按预期在主线程上执行。

    public void LoadCustomers()
    {
        // Update UI to show spinner
        this.LoadingCustomers = true;

        Task.Run(async () =>            
        {
            var customers = await this.custService.GetCustomers();
            // code truncated for clarity

            Device.BeginInvokeOnMainThread(() => 
            {
                // Update UI to hide spinner
                this.LoadingCustomers = false;
            });
        });
    }

我的问题; 有没有更好的方法来使用 ContinueWith/ConfigureAwait 选项编写此逻辑?使用这些选项似乎会阻塞 UI 线程。在下面的示例中,UI 线程是否应该继续运行 UI 逻辑(动画微调器/用户输入)然后回来完成 ​​ContinueWith 内的逻辑?

    public void LoadCustomers()
    {
        // Update UI to show spinner
        this.LoadingCustomers = true;

        this.custService.GetCustomers().ContinueWith((t) =>
        {
            var customers = t.Result;
            // code truncated for clarity

            // Update UI to hide spinner
            this.LoadingCustomers = false;
        });
    }

根据评论中的要求,这里是 GetCustomers 的代码。dbContext 是 EntityFrameworkCore。

    public async Task<List<CustomerModel>> GetCustomers()
    {
        return await this.dbContext.Customers.ToListAsync();
    }

更新

然而,FCin 的回答是正确的;这似乎与 EFCore 和 ToListAsync 有关,它不是异步运行的。

标签: c#multithreadingasynchronousxamarin.forms

解决方案


编写这种方法的正确方法是async/await从头到尾使用。现在你正在做火并忘记意义,如果里面有异常,Task.Run你永远不会知道它。您应该从事件处理程序开始。这可以是任何东西,鼠标单击,页面加载等。

private async void MouseEvent_Click(object sender, EventArgs args)
{
    await LoadCustomers();
}

public async Task LoadCustomers()
{
    // Update UI to show spinner
    this.LoadingCustomers = true;

    // We don't need Device.BeginInvokeOnMainThread, because await automatically 
    // goes back to calling thread when it is finished
    var customers = await this.custService.GetCustomers();

    this.LoadingCustomers = false;
}

有一种简单的方法可以记住何时使用Task.Run. Task.Run 在您执行 CPU 限制的操作时使用,例如计算 PI 的位数。


推荐阅读