c#-4.0 – 限制流式资源并行操作的进度

我发现自己最近使用SemaphoreSlim类来限制(大)流资源上可并行操作的进行中的工作:

// The below code is an example of the structure of the code,there are some 
// omissions around handling of tasks that do not run to completion that should be in production code

SemaphoreSlim semaphore = new SemaphoreSlim(Environment.ProcessorCount * someMagicNumber);
foreach (var result in StreamResults()) 
{
  semaphore.Wait();
  var task = DoWorkAsync(result).ContinueWith(t => semaphore.Release());
  ...
}

这是为了避免将太多结果带入内存并且程序无法应对(通常通过OutOfMemoryException证明).尽管代码有效并且性能合理,但它仍然感觉笨拙.值得注意的是,someMagicNumber乘数虽然通过分析进行了调整,但可能不尽如人意,并且不能适应DoWorkAsync实现的变化.

就像线程池可以克服调度许多事情来执行的障碍一样,我希望能够克服根据可用资源调度许多要加载到内存中的障碍的障碍.

由于决定是否会发生OutOfMemoryException确定无法确定,我感谢我所寻找的东西可能只能通过统计手段实现,甚至根本不能实现,但我希望我遗漏了一些东西.

解决方法

在这里,我要说你可能已经过度思考这个问题了.超调的后果相当高(程序崩溃).过低的后果是程序可能会放慢速度.只要您仍然有一些超出最小值的缓冲区,缓冲区的进一步增加通常几乎没有效果,除非管道中该任务的处理时间非常不稳定.

如果你的缓冲区不断填满它通常意味着管道中的任务比它之后的任务执行得快得多,所以即使没有相当小的缓冲区,它也可能始终确保跟随它的任务有一些工作.获得缓冲区90%的好处所需的缓冲区大小通常非常小(可能是几十个项目),而获得OOM错误所需的一侧则比6级高位更高.只要你介于这两个数字之间(这是一个非常大的范围),你就可以了.

只需运行您的静态测试,选择一个静态数字,也许可以为“以防万一”添加额外的几个额外费用,你应该是好的.最多,我会将一些魔术数字移动到配置文件中,以便在输入数据或机器规格发生根本变化的情况下,无需重新编译即可对其进行更改.

相关文章

目录简介使用JS互操作使用ClipLazor库创建项目使用方法简单测...
目录简介快速入门安装 NuGet 包实体类User数据库类DbFactory...
本文实现一个简单的配置类,原理比较简单,适用于一些小型项...
C#中Description特性主要用于枚举和属性,方法比较简单,记录...
[TOC] # 原理简介 本文参考[C#/WPF/WinForm/程序实现软件开机...
目录简介获取 HTML 文档解析 HTML 文档测试补充:使用 CSS 选...