Task.Run 或 Task.Factory.StartNew 是 windows phone 或任何其他客户端平台的不良做法吗?
Is Task.Run or Task.Factory.StartNew are bad practice for windows phone or any other client platform?
我有一个经常使用网络服务的 WP 8.1 应用程序,我希望它尽可能保持响应。来自 iOS dev expierense - 有一个严格的规则:"Do not do in UI thread any complex calculations! Doesnt matter how you will reach this: with blocks or with GCD".
并非所有 API 都有异步版本的问题,例如JSON.NET、SQLite 或应用程序中任何自己的复杂算法。我读了很多 articles that are defining Task.Run and Task.Factory.StartNew as bad practice + this.
那么,这样写代码好不好?它会导致一些 cpu overloading/battery drain/stability 问题吗?如果异步包装器不是个好主意 - 使复杂操作异步(后台线程)的正确方法是什么?
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;
}
}
Stephen toub 的文章说在 库 中公开同步方法的异步包装器是不好的。那没有增加任何价值。如果开发者愿意,他可以随时调用 Task.Run(()=> SomeSynchronousMethod());
。无需在库中公开它。如果它是一个应用程序,是的,你可以,因为这是你可以减轻工作负担的唯一方法。
同样适用于 "Newtonsoft.Json"。因为它是图书馆。
Is Task.Run or Task.Factory.StartNew a bad practice for windows phone
or any other client platform?
是也不是。
如果你有一些繁重的计算要做。说图像处理或类似的东西。无论如何,您都必须这样做;它需要一些 cpu 周期。无论您 运行 是什么主题,都需要一些 cpu 时间。这意味着您必须消耗 cpu,当然还有电池。
Is Task.Run or StartNew bad?
当你有 CPU 绑定工作时就不是这样了。这就是他们的目的。
如果你需要完成你的工作,你需要一个线程,它不能是 UI 线程(我们需要它来响应)。因此,使用 Task.Run 或 StartNew 借用 ThreadPool 线程没有错。
When it is bad?
如果你在可以使用自然异步的时候使用它是不好的API。网络 I/O、文件 I/O 等本质上是异步的。 You don't need a thread to invoke truly asynchronous operation.
使用线程进行 IO 只是在浪费线程,坐等底层设备完成 IO 之前什么也不做。
简而言之,对 CPU 绑定使用 Task.Run,对 IO 绑定操作自然异步 API。
我相信您误解了您提到的文章(Stephen Toub 的)。那篇文章一般不讨论 Task.Run()
等的使用。相反,他是在评论 库 是否应该将其基本同步操作包装在任务中,并将其公开为库 API.
的一部分
来自 Toub 的文章:
If a developer needs to achieve responsiveness or parallelism with synchronous APIs, they can simply wrap the invocation with a method like Task.Run
即用 Task.Run()
或类似的方法包装同步 API 也不错,只要这是 client 代码的开发人员的选择。
至于如果您作为客户端代码的开发人员这样做会产生什么影响,那完全取决于 API.
首先,对于固有的异步操作,最好使用已经支持异步操作的 API。例如,网络 I/O。任何提供对网络协议的高级访问的体面的库都应该提供某种异步 API,如果不是 async
兼容的。
但是,如果您不得不使用仅具有同步方法的库,即使对于 I/O 或其他类型的异步行为,您实际上可以使用异步调用来包装它们。
Will it cause some cpu overloading/battery drain/stability issues?
我认为在任何情况下都不会出现此类重大问题。如果操作涉及 I/O,那么在您等待数据实际到达时 CPU 不会很忙。对于其他任务,将工作卸载到后台线程涉及的开销很小;假设确实需要首先将工作排除在 UI 线程之外,那么工作本身就非常昂贵 CPU-wise,额外的 CPU 利用率来管理后台任务将可以忽略不计。
我有一个经常使用网络服务的 WP 8.1 应用程序,我希望它尽可能保持响应。来自 iOS dev expierense - 有一个严格的规则:"Do not do in UI thread any complex calculations! Doesnt matter how you will reach this: with blocks or with GCD".
并非所有 API 都有异步版本的问题,例如JSON.NET、SQLite 或应用程序中任何自己的复杂算法。我读了很多 articles that are defining Task.Run and Task.Factory.StartNew as bad practice + this.
那么,这样写代码好不好?它会导致一些 cpu overloading/battery drain/stability 问题吗?如果异步包装器不是个好主意 - 使复杂操作异步(后台线程)的正确方法是什么?
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;
}
}
Stephen toub 的文章说在 库 中公开同步方法的异步包装器是不好的。那没有增加任何价值。如果开发者愿意,他可以随时调用 Task.Run(()=> SomeSynchronousMethod());
。无需在库中公开它。如果它是一个应用程序,是的,你可以,因为这是你可以减轻工作负担的唯一方法。
同样适用于 "Newtonsoft.Json"。因为它是图书馆。
Is Task.Run or Task.Factory.StartNew a bad practice for windows phone or any other client platform?
是也不是。
如果你有一些繁重的计算要做。说图像处理或类似的东西。无论如何,您都必须这样做;它需要一些 cpu 周期。无论您 运行 是什么主题,都需要一些 cpu 时间。这意味着您必须消耗 cpu,当然还有电池。
Is Task.Run or StartNew bad?
当你有 CPU 绑定工作时就不是这样了。这就是他们的目的。
如果你需要完成你的工作,你需要一个线程,它不能是 UI 线程(我们需要它来响应)。因此,使用 Task.Run 或 StartNew 借用 ThreadPool 线程没有错。
When it is bad?
如果你在可以使用自然异步的时候使用它是不好的API。网络 I/O、文件 I/O 等本质上是异步的。 You don't need a thread to invoke truly asynchronous operation.
使用线程进行 IO 只是在浪费线程,坐等底层设备完成 IO 之前什么也不做。
简而言之,对 CPU 绑定使用 Task.Run,对 IO 绑定操作自然异步 API。
我相信您误解了您提到的文章(Stephen Toub 的)。那篇文章一般不讨论 Task.Run()
等的使用。相反,他是在评论 库 是否应该将其基本同步操作包装在任务中,并将其公开为库 API.
来自 Toub 的文章:
If a developer needs to achieve responsiveness or parallelism with synchronous APIs, they can simply wrap the invocation with a method like Task.Run
即用 Task.Run()
或类似的方法包装同步 API 也不错,只要这是 client 代码的开发人员的选择。
至于如果您作为客户端代码的开发人员这样做会产生什么影响,那完全取决于 API.
首先,对于固有的异步操作,最好使用已经支持异步操作的 API。例如,网络 I/O。任何提供对网络协议的高级访问的体面的库都应该提供某种异步 API,如果不是 async
兼容的。
但是,如果您不得不使用仅具有同步方法的库,即使对于 I/O 或其他类型的异步行为,您实际上可以使用异步调用来包装它们。
Will it cause some cpu overloading/battery drain/stability issues?
我认为在任何情况下都不会出现此类重大问题。如果操作涉及 I/O,那么在您等待数据实际到达时 CPU 不会很忙。对于其他任务,将工作卸载到后台线程涉及的开销很小;假设确实需要首先将工作排除在 UI 线程之外,那么工作本身就非常昂贵 CPU-wise,额外的 CPU 利用率来管理后台任务将可以忽略不计。