2014-03-28 24 views
0

考虑这样的代码:如果完全异步,我的任务是否长时间运行?

private static async Task ProcessSomethingAsync() 
{ 
    while (true) 
    { 
     var message = await GetMessageAsync(); 
     await WriteAsync(message); 
    } 
} 

考虑到GetMessageAsyncWriteAsync方法杠杆异步IO。

想象一下,我有几个(从2到N)这样的任务,只要应用程序存在,它就一直存在。 我认为,因为循环内的代码是完全异步的,所以最好不要在启动这样的任务时使用LongRunning选项,以便我们能够利用ThreadPool而不是为每个Task创建线程。

这是正确的还是我错过了什么?

+0

如果这些方法实际上是异步I/O,而不是CPU绑定,那么它们可以在一个线程内生活得很好。当然,如果主线程没有被占用,但即使这样,你也可以在另一个线程中执行所有这些。 – Luaan

+0

'GetMessageAsync()'和/或'WriteAsync()'实际上可以同步完成吗?请记住,如果它们实际上完全同步完成,那么'await'实际上并不代表该线程实际上将被放弃的时间点。 –

+0

@presiuslitelsnoflek同意,术语异步和长时间运行是正交的,但也许我应该改变问题更具体。 – Max

回答

5

当我启动这样的任务时,最好不要使用LongRunning选项,以便我们能够利用ThreadPool而不是每个Task创建线程。

当您运行async代码时,您不应指定LongRunning。如果你这样做,那么(截至今天的实现),线程池将启动一个新线程来运行你的async代码的第一部分。只要您的代码在await处产生,该新线程将被处置,其余代码将在常规线程池线程上运行。所以,LongRunning通常适用于async的代码。

我为什么StartNew is dangerous一篇博客文章中,我(暂时的)涵盖所有TaskCreationOptions在那个岗位:

AttachedToParent不应该在异步任务中使用,所以这是的。 DenyChildAttach应该总是与异步任务一起使用(提示:如果您还不知道,那么StartNew不是您需要的工具)。 DenyChildAttach由Task.Run传递。 HideScheduler可能在一些非常模糊的调度场景中很有用,但通常应避免异步任务。这只剩下LongRunning和PreferFairness,它们都是只应在应用程序分析后指定的优化提示。我经常看到LongRunning特别被滥用。在绝大多数情况下,线程池将在0.5秒内调整为任何长时间运行的任务 - 而不是 LongRunning标志。很可能,你并不需要它。

+1

有趣的是,'LongRunning'似乎启动一个普通的线程,而不是一个池线程。 'Thread.IsThreadPoolThread'对它来说是'false'。所以即使有ThreadPool饥饿,它也会立即开始。 – Noseratio

+0

这正是我的想法。我也看到了你的文章。谢谢。 – Max

+0

@Noseratio ThreadPool适用于相对较短的代码段,所以明确标记为长时间运行的代码不会在那里运行。 – svick

1

是,指定LongRunning将可能允许创建多个线程,因为你是在告诉你的任务是要养猪线程长一段时间的调度。

异步方法正好相反,他们释放线程来做其他事情而不会阻塞。