Страницы

Поиск по вопросам

суббота, 21 декабря 2019 г.

Почему async/await блокирует UI? [дубликат]

#c_sharp #xamarin #async_await


        
             
                
                    
                        
                            This question already has an answer here:
                            
                        
                    
                
                        
                            Зависает оператор `await` в оконном приложении / программа
висит при вызове Task.Result или Wait
                                
                                    (1 ответ)
                                
                        
                                Закрыт 1 год назад.
            
                    
Пытаюсь разобраться с async/await.

Вызываю асинхронный метод:

public static async Task GetData(string url)
{
    dynamic results = await DataService.getData(url);
}


Cам метод:

public static async Task getData(string url)
{
    HttpClient client = new HttpClient();
    var response = await client.GetAsync(url);
    while(true){} // специально сделанное зацикливание, чтобы увидеть что UI не блокируется
    dynamic data = null;
    if(response !=null)
    {
        string json = response.Content.ReadAsStringAsync().Result;
        data = JsonConvert.DeserializeObject(json);
    }
    return data;
}


Однако при вызове этого метода всё зависает. Почему все зависает, ведь на сколько
я понимаю, async\await должен создаваться в отдельном потоке и следовательно не должен
блочить UI, а просто зацикливаться в "фоновом" потоке?
    


Ответы

Ответ 1



Нет, вы понимаете неправильно. Если async-функция запущена в UI-потоке, она в нём и выполняется (это можно легко увидеть, залогировав Id потока), за исключением await’ов, во время которых функция вообще нигде не выполняется (и тем самым освобождает UI-поток). Иначе как бы можно было получать доступ к UI-контролам в async-функции? Уберите вечный цикл, он завешивает UI. Что потенциально может вывести async-функцию в другой поток — это ConfigureAwait(false), но в вашей функции его нет. У вас ошибка в строке string json = response.Content.ReadAsStringAsync().Result; Вы не должны синхронно дожидаться завершения Task’а ReadAsStringAsync(). Замените это на string json = await response.Content.ReadAsStringAsync(); Кстати, у вас есть ещё одна потенциально медленная операция в UI-потоке: JsonConvert.DeserializeObject(json). Вынесите её в фоновый поток при помощи data = await Task.Run(() => JsonConvert.DeserializeObject(json)); По поводу механики (как именно работает async-функция на нижнем уровне) можно почитать, например, тут, тут, тут, тут, тут и тут. И посмотреть тут.

Комментариев нет:

Отправить комментарий