使用自己的ThreadPool继续任务

时间:2014-05-30 16:32:44

标签: c# .net task-parallel-library async-await

是否可以强制继续使用async-await语句在自定义ThreadPool的线程上运行?

背景信息:我正在运行ASP应用程序并在后台完成相当多的工作。我通过自编写的ThreadPool完成所有工作,但是如果我使用async-await模式,则延续始终在名为" Worker Thread"的线程上运行。 我非常确定这是来自默认ThreadPool的线程,它也用于处理HTTP请求。 由于默认ThreadPool的所有线程都忙着继续我的后台工作,这导致这些请求的饥饿。

2 个答案:

答案 0 :(得分:5)

是。您可以创建适用于自定义ThreadPool的自定义SynchronizationContext,并在运行异步操作之前对其进行设置。

var prevCtx = SynchronizationContext.Current; 
try 
{
    SynchronizationContext.SetSynchronizationContext(new ThreadPoolSynchronizationContext()); 

    // async operations.
} 
finally 
{  
    SynchronizationContext.SetSynchronizationContext(prevCtx); 
} 

有关如何创建自定义SynchronizationContext的更多信息:Await, SynchronizationContext, and Console Apps


虽然很少需要自定义ThreadPool。您可能应该尝试使用内置的优化进行优化。

答案 1 :(得分:4)

我认为您不需要自定义线程池,特别是如果您正在进行大量自然使用IOCP线程的并行I / O.这适用于任何其他只在任务完成时从池中获取线程的API(例如Task.Delay)。

通常你会await task.ConfigureAwait(false)继续在task完成的同一个帖子上发生:

// non-IOCP (worker) continuation thread 
await Task.Delay(1000).ConfigureAwait(false); 
// IOCP continuation thread
await stream.ReadAsync(buff, 0, buff.Length).ConfigureAwait(false); 

现在,在ASP.NET中,您甚至不需要使用ConfigureAwait。 ASP.NET AspNetSynchronizationContext没有为await延续保持线程关联, WinFormsSynchronizationContextDispatcherSynchronizationContext不同UI应用。您的延续将在任务已完成的任何线程上运行,原样。 AspNetSynchronizationContext只是"进入"该线程上的ASP.NET上下文,以确保您的代码可以访问HttpContext和其他相关的ASP.NET请求环境状态信息。

您可以将ThreadPool.SetMinThreads的默认IOCP和工作线程数增加到ThreadPool stuttering problems

如果自定义线程池的唯一原因是限制任务的并行度,请使用TPL数据流或仅SemaphoreSlim.WaitAsync(检查"Throttling asynchronous tasks")。

也就是说,如果实现自定义等待,您可以非常精确地控制Task延续。检查this question以获取该基本示例。