Task对象只能用于线程池线程吗?

时间:2012-11-08 22:56:36

标签: .net multithreading asynchronous task c#-5.0

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

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

作为关于不在线程池中运行长时间运行代码的规则的后续问题 - 这个规则是关于cpu密集的代码吗?如果你的代码运行很长时间(例如72小时)但是花费大部分时间做“await Task.Delay()”这样的事情怎么办呢?那么可以使用线程池线程,或者应该使用“常规”你的并发代码需要运行很长时间的所有情况下的线程?

2 个答案:

答案 0 :(得分:3)

您可以通过自定义Task在任意位置投放TaskScheduler

但是,如果你所做的只是await Task.Delay(),你就不应该打扰 异步调用的全部目的是在等待某事发生时不要占用线程。 在等待Task.Delay()时,根本没有运行任何线程。

如果您实际上长时间运行同步代码,则可以指定TaskCreationOptions.LongRunning以强制它创建新线程。

答案 1 :(得分:3)

  

我也读过一个不应该在线程池线程上启动长时间运行的代码

线程池正确响应长时间运行的代码,因此它不像不能那样做 - 它不是最有效的< / em>这样做的方式。

另请注意,Task.Delay暗示“长跑”的相反 - 个人Task实际上在await处完成,并且不是线程池上的时间更长。当Task完成时,将创建另一个Task.Delay并将其排队到线程池。 Task返回的Task.Run(当您传递async委托时)实际上是代表整个代表的“代理Task”。

  

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

在您的情况下,您不需要它,但 是可能的。我的AsyncEx library包含AsyncContextThread类型,该类型公开了TaskFactory属性,您可以使用该属性在该主题上启动Task

  

我正在使用Task.Run()

“并行”为所有实例提供服务

在您的情况下,您根本不需要Task.RunTaskFactory。您可以轻松地并行执行此操作,而无需将工作明确地发送到线程池:

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();
}