[英]Force TPL Tasks to run on a single core
我有 ETL 项目,它有一些处理组件。 单个组件是基于 BlockingCollection 的生产者-消费者。 所有组件都通过 Task.Run 并行执行,等待来自其他组件的项目到达,处理它们并将结果放入它们的输出集合(想想管道)。 所有组件都通过 Task.Run() 执行。
是否可以强制任务在单核上运行(我不希望它们占用 100% 的多核 CPU)而不为进程设置处理器关联(这似乎有点矫枉过正)?
请注意,我仍然希望任务以并行方式运行 - 仅在单个内核上运行。
任务在线程上执行,操作系统决定它执行哪个核心。
我认为除了设置 Processor Affinity 之外没有其他任何方法。
请参阅此处: https : //msdn.microsoft.com/en-us/library/system.diagnostics.processthread.processoraffinity.aspx
您确定在一个内核上并行运行它们将使您受益于性能,为什么您不希望该进程在需要时可能使用 100% cpu? 操作系统仍然会优先考虑其他进程,而不是一定允许这样做
如果您担心您的进程对其他操作系统进程造成压力,您也可以降低线程/进程优先级:
进程优先级: https : //msdn.microsoft.com/en-us/library/system.diagnostics.process.priorityclass.aspx线程优先级: https : //msdn.microsoft.com/en-us/library/system.threading .thread.priority(v=vs.110).aspx
是的,这是完全可能的。 你只需要实现你自己的TaskScheduler 。
实际上,TaskSchduler 的 API 文档中的示例说明了如何准确完成您想要的操作——它们实现了LimitedConcurrencyLevelTaskScheduler
,让您可以设置要使用的工作线程数。
API 文档的备注部分中的链接也很有价值。 使用 .NET Framework 4项目进行并行编程的示例包含大量替代线程调度程序,在此处详细描述。 它们可能会激发您思考安排这些任务的替代方法。
这里唯一的扭曲是您不能再使用Task.Run()
快捷方式——您需要通过 TaskFactory 来代替。
使用Task.Run()
,您对作业的控制非常低,并且一切都是并行的,除非您使用自定义调度程序。
我建议使用Task Parallel Library (TPL)而不是这种技术解决方案,它可以被视为处理线程作业的更高层。
在 TPL 中,您可以选择块类型来处理您的数据,甚至可以将它们之间的块连接起来,这样当一个项目刚刚完成处理时,结果就可以在下一个 TPL 块中排队。
您可以使用ActionBlock<T>
:您定义要为每个要处理的项目执行的代码,并且当数据可用于 ActionBlock 时,使用.Post()
,它会自动处理......并行。 但根据您的需要,您可以指定MaxDegreeOfParallelism=1
。
因此,使用这种方法,您无法控制执行代码的核心,但您可以确保所有项目都将按顺序处理,并且一次不会使用多个核心。
var workerBlock = new ActionBlock<int>(
// Simulate work by suspending the current thread.
millisecondsTimeout => Thread.Sleep(millisecondsTimeout),
// Specify a maximum degree of parallelism.
new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = 1
});
// Source: https://docs.microsoft.com/fr-fr/dotnet/api/system.threading.tasks.dataflow.actionblock-1?view=netcore-3.1
你也可以阅读这篇关于 TPL 的完整文章,非常有趣。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.