Task.Run затем вызывать альтернативу основного потока, используя async, ожидают ContinueWith? - PullRequest
0 голосов
/ 14 сентября 2018

Следующий код работает отлично. Он показывает счетчик в пользовательском интерфейсе, запускает задачу, используя поток из пула потоков, и выполняет тяжелую операцию, после завершения которой логика, позволяющая скрыть счетчик, выполняется в основном потоке, как и предполагалось.

    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? Использование этих параметров, кажется, блокирует поток пользовательского интерфейса. В приведенном ниже примере, не должен ли поток пользовательского интерфейса продолжать выполнение логики пользовательского интерфейса (анимация вращающегося / пользовательского ввода) и затем возвращаться для завершения логики внутри 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();
    }

UPDATE

Однако ответ от FCin правильный; Причина этого, по-видимому, связана с EFCore и ToListAsync, он не работает асинхронно.

Ответы [ 2 ]

0 голосов
/ 14 сентября 2018

Правильный способ написания такого метода - использовать 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 только , когда выполняете какие-либо операции с процессором, такие как вычисление цифр PI.

0 голосов
/ 14 сентября 2018

РЕДАКТИРОВАТЬ: @ bradley-uffner предложил просто написать следующее:

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

    var customers = await this.custService.GetCustomers();
    // code truncated for clarity

    // you are still on UI thread here
    this.LoadingCustomers = false;
}

Как насчет этого:

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

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

    this.LoadingCustomers = false;
}

Код после await выполняется в текущем потоке, поэтому он должен работать «из коробки».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...