Task.Run или Task.Factory.StartNew - это плохая практика для Windows Phone или любой другой клиентской платформы?
У меня есть приложение WP 8.1, которое часто использует веб-сервис, и я хочу, чтобы оно было максимально отзывчивым. Из iOS dev expierense - есть одно строгое правило: "Не делайте в потоке пользовательского интерфейса никаких сложных вычислений! Не имеет значения, как вы достигнете этого: с помощью блоков или с GCD".
Проблема в том, что не все API имеют асинхронные версии, например, JSON.NET, SQLite или какой-либо собственный сложный алгоритм в приложении. Я прочитал много статей, которые определяют Task.Run и Task.Factory.StartNew как плохую практику + это.
Так хорошо ли писать такой код? Это вызовет некоторые перегрузки процессора / разрядку батареи / проблемы со стабильностью? Если асинхронные оболочки являются плохой идеей - как правильно сделать асинхронные сложные операции (фоновый поток)?
protected async Task<T> GetDataAsync<T>(string uriString, CancellationToken cancellationToken = default(CancellationToken))
{
var uriToLoad = new Uri(uriString);
using (var httpClient = new HttpClient())
{
var response= await httpClient.GetAsync(uriToLoad, cancellationToken).ConfigureAwait(false);
response.EnsureSuccessStatusCode();
cancellationToken.ThrowIfCancellationRequested();
var dataString = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested();
// async wrapped call to sync API
var result = await Task.Factory.StartNew(() => JsonConvert.DeserializeObject<T>(dataString), cancellationToken).ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested();
return result;
}
}
2 ответа
В статье Стивена Тауба говорится, что разоблачение асинхронных оболочек для синхронных методов в библиотеке - это плохо. Это не добавляет никакой ценности. Если разработчик хочет, он всегда может позвонить Task.Run(()=> SomeSynchronousMethod());
, Нет необходимости выставлять его в библиотеке. Если это приложение, да, вы можете, потому что это единственный способ загрузить работу.
То же самое относится и к "Newtonsoft.Json". потому что это библиотека.
Task.Run или Task.Factory.StartNew - это плохая практика для Windows Phone или любой другой клиентской платформы?
И да и нет.
Если у вас есть тяжелые вычисления, чтобы сделать. Скажем, обработка изображений или что-то в этом роде. Вам все равно придется это сделать; Нужно несколько циклов процессора. Независимо от того, какой поток вы запускаете, ему понадобится некоторое количество процессорного времени. Это означает, что вы должны потреблять процессор и, конечно, батарею.
Task.Run или StartNew это плохо?
Не совсем, когда вы работаете с процессором. Вот для чего они.
Если вам нужно выполнить свою работу, вам нужен поток, он не может быть потоком пользовательского интерфейса (нам нужно, чтобы он был отзывчивым). Итак, нет ничего плохого в том, чтобы заимствовать поток ThreadPool с помощью Task.Run или StartNew.
Когда это плохо?
Это плохо, если вы используете его, когда вы можете использовать естественно асинхронный API. Сетевой ввод-вывод, файловый ввод-вывод и т. Д. Изначально являются асинхронными. Вам не нужен поток для вызова действительно асинхронной операции.
Использовать потоки для ввода-вывода - это просто тратить поток, сидя и ничего не делая, пока базовое устройство не завершит ввод-вывод.
Вкратце, используйте Task.Run для привязки к процессору и, естественно, асинхронный API для операций ввода-вывода.
Я полагаю, вы неправильно поняли статью, на которую ссылались (Стивена Туба). Эта статья не обсуждает использование Task.Run()
и т.д. в общем. Скорее, он комментирует, должна ли библиотека обернуть свои принципиально синхронные операции в задачах и представить это как часть API библиотеки.
Из статьи Тауба:
Если разработчику необходимо добиться отзывчивости или параллелизма с помощью синхронных API, он может просто обернуть вызов с помощью метода, такого как Task.Run.
Т.е. не плохо оборачивать синхронный API с Task.Run()
или аналогичные, если это выбор разработчика клиентского кода.
Насколько это имеет значение, если вы, как разработчик клиентского кода, делаете это, зависит полностью от API.
Во-первых, определенно предпочтительнее использовать для изначально асинхронных операций API, который уже поддерживает это. Например, сетевой ввод / вывод. Любая приличная библиотека, обеспечивающая высокоуровневый доступ к сетевым протоколам, должна предоставлять какой-то асинхронный API, если не async
-совместимый
Но если вы застряли в необходимости использовать библиотеку, которая имеет только синхронные методы даже для ввода-вывода или других видов асинхронного поведения, вы можете фактически обернуть их асинхронным вызовом.
Это вызовет некоторые перегрузки процессора / разрядку батареи / проблемы со стабильностью?
Ни в коем случае я не ожидал бы, что будут существенные проблемы тех видов. Если операция включает в себя ввод-вывод, то процессор не будет занят, пока вы ожидаете фактического поступления данных. Для других задач выгрузка работы в фоновый поток требует незначительных затрат; если предположить, что на самом деле необходимо не допустить работу из потока пользовательского интерфейса, то сама работа настолько затратна с точки зрения использования ЦП, что дополнительная загрузка ЦП для управления фоновой задачей будет незначительной.