3

c# 5.0 中新的异步语言特性在很大程度上依赖于 Task 对象,许多示例表明,在 Task 中运行某些代码的一种常见方法是通过 Task.Run() 启动它,它将您的代码表示为任务并在线程池线程上运行它。

但是,我也读过不应该在线程池线程上启动长时间运行的代码,这让我想到了这个问题:是否仍然可以使用所有 C# 异步语言功能(例如 Task、'await'、'async ') 在“常规”线程上而不使用线程池?在这种情况下,如何获得一个代表在“常规”线程上运行的代码的 Task 对象?

作为关于不在线程池中运行长时间运行代码的规则的后续问题 - 该规则是否仅适用于 CPU 密集型代码?如果您的代码运行了很长时间(例如 72 小时),但大部分时间都花在做诸如“等待 Task.Delay()”之类的事情上怎么办……那么可以使用线程池线程,还是应该使用“常规”?并发代码需要长时间运行的所有情况下的线程?

4

2 回答 2

3

You can run Tasks wherever you want by making a custom TaskScheduler.

However, if all you're doing is await Task.Delay(), you shouldn't bother.
The whole purpose of asynchronous calls is to not hold up a thread while waiting for something to happen. While you're awaiting Task.Delay(), there aren't any threads running at all.

If you're actually running synchronous code for a long time, you can specify TaskCreationOptions.LongRunning to force it to create a new thread.

于 2012-11-08T22:58:41.743 回答
3

我还读到不应在线程池线程上启动长时间运行的代码

线程池正确响应长时间运行的代码,所以这并不是你做不到——这不是最有效的方法。

另请注意,这Task.Delay意味着与“长时间运行”相反 - 个人实际上Task在该点完成await并且不再在线程池中。另一个在完成Task时被创建并排队到线程池中Task.DelayTask返回的(Task.Run当你传递一个async委托时)实际上是一个Task代表整个委托的“代理”。

是否仍然可以在“常规”线程上使用所有 C# 异步语言功能(例如 Task、'await'、'async')而不使用线程池?

在你的情况下,你不需要它,但它可能的。我的AsyncEx 库包含一个AsyncContextThread类型,该类型公开一个TaskFactory属性,您可以使用该属性Task在该线程上启动 s。

我正在使用 Task.Run() “并行”为所有实例提供服务

就您而言,您根本不需要Task.Run或根本不需要TaskFactory。您可以轻松地并行执行此操作,而无需显式将工作发送到线程池:

string[] instanceNames = ...;
var tasks = instanceNames.Select(ServiceInstanceAsync);
await Task.WhenAll(tasks);

private static async Task ServiceInstanceAsync(string name)
{
  await DownloadAndProcessFileAsync();
  await Task.Delay(15000);
  await ExecuteSSHAsync();
}
于 2012-11-09T00:10:16.293 回答