可以将其当前计数减少 N (N>=1) 的信号量?

2023-12-08

我正在实现一个流量控制组件,限制可以发送的最大请求。每个工作线程可以发送单个请求或一批请求,但任何时候待处理请求的总数都不应超过最大数量。

我最初想用 SemaphoreSlim 来实现: 将信号量初始化为最大请求计数,然后当工作线程要调用服务时,它必须获取足够数量的令牌,但是我发现实际上 SemaphoreSlim 和 Semaphore 只允许线程将信号量计数减少 1,在我的情况下我想要减少工作线程承载的请求数。

我应该在这里使用什么同步原语?

需要澄清的是,该服务支持批处理,因此一个线程可以在一次服务调用中发送 N 个请求,但相应地它应该能够将信号量的当前计数减少 N。


下面是定制的SemaphoreManyFifo提供方法的类Wait(int acquireCount)方法和Release(int releaseCount)。其行为严格遵循先进先出原则。它具有相当不错的性能(在我的 PC 中,8 个线程每秒约 500,000 次操作)。

public class SemaphoreManyFifo : IDisposable
{
    private readonly object _locker = new object();
    private readonly Queue<(ManualResetEventSlim, int AcquireCount)> _queue;
    private readonly ThreadLocal<ManualResetEventSlim> _pool;
    private readonly int _maxCount;
    private int _currentCount;

    public int CurrentCount => Volatile.Read(ref _currentCount);

    public SemaphoreManyFifo(int initialCount, int maxCount)
    {
        // Proper arguments validation omitted
        Debug.Assert(initialCount >= 0);
        Debug.Assert(maxCount > 0 && maxCount >= initialCount);
        _queue = new Queue<(ManualResetEventSlim, int)>();
        _pool = new ThreadLocal<ManualResetEventSlim>(
            () => new ManualResetEventSlim(false), trackAllValues: true);
        _currentCount = initialCount;
        _maxCount = maxCount;
    }
    public SemaphoreManyFifo(int initialCount) : this(initialCount, Int32.MaxValue) { }

    public void Wait(int acquireCount)
    {
        Debug.Assert(acquireCount > 0 && acquireCount <= _maxCount);
        ManualResetEventSlim gate;
        lock (_locker)
        {
            Debug.Assert(_currentCount >= 0 && _currentCount <= _maxCount);
            if (acquireCount <= _currentCount && _queue.Count == 0)
            {
                _currentCount -= acquireCount; return; // Fast path
            }
            gate = _pool.Value;
            gate.Reset(); // Important, because the gate is reused
            _queue.Enqueue((gate, acquireCount));
        }
        gate.Wait();
    }

    public void Release(int releaseCount)
    {
        Debug.Assert(releaseCount > 0);
        lock (_locker)
        {
            Debug.Assert(_currentCount >= 0 && _currentCount <= _maxCount);
            if (releaseCount > _maxCount - _currentCount)
                throw new SemaphoreFullException();
            _currentCount += releaseCount;
            while (_queue.Count > 0 && _queue.Peek().AcquireCount <= _currentCount)
            {
                var (gate, acquireCount) = _queue.Dequeue();
                _currentCount -= acquireCount;
                gate.Set();
            }
        }
    }

    public void Dispose()
    {
        foreach (var gate in _pool.Values) gate.Dispose();
        _pool.Dispose();
    }
}

在上述实现中添加对超时和取消的支持并非易事。它将需要一个不同的(可更新的)数据结构而不是Queue<T>.


原本的Wait+Pulse实现可以在第一次修订这个答案。它很简单,但缺乏理想的 FIFO 行为。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

可以将其当前计数减少 N (N>=1) 的信号量? 的相关文章

  • fopen_s 怎么会比 fopen 更安全呢?

    我正在处理遗留代码Windows平台 当我编译代码时VS2013 它给出以下警告 错误 C4996 fopen 该函数或变量可能不安全 考虑使用fopen s反而 要禁用弃用 请使用 CRT SECURE NO WARNINGS 详情请参见
  • Linq - 从表达式 创建表达式

    我有一个谓词Expression
  • 如何在特定时间以毫秒精度触发 C# 函数?

    我有两台计算机 它们的时间通过 NTP 同步 确保时间仅相差几毫秒 其中一台计算机将通过 TCP 向另一台计算机发送一条消息 以在两台计算机上的未来指定时间启动某个 c 函数 我的问题是 如何在特定时间以毫秒精度 或更好 触发 C 中的函数
  • NDK 应用 onDestroy 清理 - 如何 DetachCurrentThread

    因此 如果我们连接 我们必须在完成后分离线程 对吗 JNIEnv get jni env JNIEnv res JAVA VM gt GetEnv void res JNI VERSION 1 6 Using cached JavaVM J
  • 将字符串作为 PChar 从 CSharp 传递到 Delphi DLL

    我正在尝试将字符串从 C 传递到 Delphi 构建的 DLL Delphi DLL 需要 PChar 这是Delphi导出 procedure DLL Message Location PChar AIntValue integer st
  • 将公历日期转换为儒略日期,然后再转换回来(随着时间)

    我正在编写一个程序 必须将当前的公历日期和时间转换为儒略日期 然后再转换回公历门 最终我需要添加能够添加年 月 日 小时 分钟和秒的功能 但我需要先解决这部分问题 现在我已经从公历日期转换为儒略日期 所以从逻辑上讲 我觉得我应该能够以某种方
  • ASP.NET - 在 RenderContent 调用中将事件处理程序添加到 Repeater 内的 LinkBut​​ton

    我有一个加载自定义用户控件的 Sharepoint WebPart 用户控件包含一个 Repeater 而 Repeater 又包含多个 LinkBut ton 在 Web 部件的 RenderContent 调用中 我有一些用于添加事件处
  • ContentDialog 未与 UWP 中心对齐

    据我所知 ContentDialog的默认行为应该是使其在 PC 上居中并在移动设备上与顶部对齐 但就我而言 即使在 PC 上我也将其与顶部对齐 但我不明白发生了什么 我正在使用代码隐藏来创建它 这是我正在使用的代码片段 Creates t
  • 组合框下拉位置

    我有一个最大化的表单 其中包含 500px 的组合框控件 停靠在右上角 Width 尝试打开组合框后 列表的一半超出了屏幕 如何强制列表显示在表单中 棘手的问题 我找不到解决这个问题的好办法 只是一个解决方法 添加一个新类并粘贴如下所示的代
  • Linq 合并列表

    我的课 public class Foo public int A get set public List
  • 对作为函数参数传递的指针使用删除

    删除作为函数参数传递的指针是否可以 并且合法 如下所示 include
  • 控制台应用程序中使用 Unicode 字符的 _tprintf

    我正在从 Unicode 构建的控制台应用程序 使用 C 和 Visual Studio 2008 执行这个简单的输出 此代码旨在在 Windows 上运行 tprintf L Some sample string n 一切正常 但是如果我
  • .NET 5 EF Core SaveChangesAsync 因错误而挂起

    尽管这个问题有很多结果 但没有一个真正给我明确的答案 每次我尝试通过 AddAsync 和 SaveChangesAsync 方法插入错误数据 例如重复的主键 时 我都会看到以下日志 执行 DbCommand 失败 15 毫秒 我还在 SQ
  • 如何从外语线程调用Python函数(C++)

    我正在开发一个程序 使用 DirectShow 来抓取音频数据 媒体文件 DirectShow 使用线程将音频数据传递给回调 我的程序中的函数 然后我让该回调函数调用另一个函数 Python 中的函数 我使用 Boost Python 来包
  • 如何构建一棵与或树?

    我需要一个支持 与 和 或 的树结构 例如 给定一个正则表达式 如ab c d e 我想把它变成一棵树 所以 一开始我们有两个 或 分支 它可以向下ab or c d e 如果你低头ab分支 你得到两个节点 a and b or a其次是b
  • valgrind 在 Raspberry Pi 上返回未处理的指令

    我最近一直在尝试在运行 Debian GNU Linux7 0 喘息 的树莓派 型号 b 上使用 valgrind 来调试分段错误 每次我在编译的 C 程序上运行 valgrind 时 都会得到类似以下内容的信息 disInstr arm
  • 选择合适的IDE

    您会推荐使用以下哪种 IDE 语言来在 Windows 下开发涉及识别手势并与操作系统交互的项目 我将使用 OpenCV 库来执行图像处理任务 之后 我将使用 win32 API 或 NET 框架与操作系统交互 具体取决于您建议的工具 性能
  • 如何从 Access 数据库中读取“是/否”值作为布尔值?

    帮我找回YES NO来自 MS Access 的布尔格式数据类型 我尝试解析它 但它总是返回 false 更新 实际上不是问题抱歉 它确实接受 YES NO 作为布尔值 OleDbconnection dbConnect new OleDb
  • 如何在 C 中创建最低有效位设置为 1 的掩码

    这个功能如何运作 最低有效 n 位设置为 1 的掩码 Example n 6 gt 0x2F n 17 gt 0x1FFFF 我根本不明白这些 尤其是 n 6 gt 0x2F 另外 什么是面膜 通常的方法是采取1 并将其左移n位 这会给你类
  • 如何使用 C# 为 azure devops 变量赋值

    我有 selenium C 测试脚本 可以从浏览器获取令牌 我有两个 azure devops 任务 一个用于执行 selenium 测试 另一个用于执行 API 测试 我想将 selenium 测试获取的令牌传递给 API 测试执行任务

随机推荐

  • 时间序列中的每小时平均值

    这是一个具有每小时智能电表数据且 freq 24 的时间序列 它是在三天内测量的 所以first day 1 24 second 25 48 third 49 72 我想要三天内每小时的平均值 例如 t 1 t 25 t 49 3 这样我就
  • 如何仅将 CSV 中的唯一值添加到 ComboBox 中?

    我想读取 csv 文件并将单词 Jakarta 和 Bandung 放入组合框中 这是输入 id from 1 Jakarta 2 Jakarta 5 Jakarta 6 Jakarta 10 Bandung 11 Bandung 12 B
  • ORA-28040: 没有匹配的身份验证协议

    即使按照以下设置 我仍然面临这个问题 更换ojdbc14 jar with ojdbc6 jar 也尝试过ojdbc5 jar Added SQLNET ALLOWED LOGON VERSION SERVER 8 到 sqlnet ora
  • 精灵套件中的裁剪/蒙版圆形图像节点会产生锯齿状边缘

    是否可以为没有锯齿状边缘的图像节点提供圆形蒙版 裁剪 按照苹果公司的这个例子 https developer apple com reference spritekit skcropnode 结果并不理想 您可以点击链接查看 let sha
  • 从服务获取登录用户名

    我有一项必须登录本地管理员才能安装的服务 此服务的目的是在用户登录或注销时记录其用户名 我终于找到了一些我认为可以工作的WMI代码 但它仍然返回管理员 为什么这不起作用 var query new ObjectQuery SELECT FR
  • 放大/缩小时保持地图上 D3 对象大小不变

    我正在遵循以下示例http bl ocks org d3noob raw 5193723 示例中绘制的圆圈在放大时会增大 我无法找出保持圆圈大小相同的方法 有任何想法吗 Edit1 关于如何保持饼弧半径恒定的任何想法 我已经找到了保持圆半径
  • WPF 网页浏览器控件与 winforms

    我正在创建一个 wpf 应用程序 其中使用网络浏览器控件 无论如何 有时我需要查找 html 元素 调用点击和其他基本功能 在 winforms webbrowser 控件中 我可以通过执行以下操作来实现此目的 webBrowser1 Do
  • 编写扩展方法来调用控件的更好方法?

    我有这个通用函数来调用 WinForm 控件 public static void Invoke this Control c Action action if c InvokeRequired c TopLevelControl Invo
  • 在 C++/Qt 中获取特定于平台的行尾字符

    有什么办法可以为任何平台获得正确的行尾符号吗 我的意思是 我可以使用 n对于 Windows 和 Unix 如果我想将 EOL 写入文件 但也有 r n如果我要在二进制数据中进行搜索 这将很重要 所以 我需要类似的东西Environment
  • 如何设置Jbutton的颜色

    如何设置 JButton 的颜色 我已经尝试过这个 button setBackground Color red 但没有成功 这只是改变按钮边框的颜色 然后我尝试覆盖paintComponents public void paintComp
  • 如何从仅包含指定类型的类成员的类/接口定义类型

    让我在这个例子中解释一下我的想法 假设我有这门课 class Class1 f1 string f2 string f3 number f4 Date 如果我需要一个带有类型成员的类型string来自那个班级 例如我可以做 type Cla
  • 对逗号分隔数字列表进行排序的 Pythonic 方法

    输入样本 20 71146620 100 26867616 10 02513583 10 52811698 100 23859051 我从文件中将其作为命令行参数读取到列表中 lin i strip for i in open sys ar
  • Android - 设置片段ID

    我怎样才能设置一个Fragment s Id这样我就可以使用getSupportFragmentManager findFragmentById R id 您无法以编程方式设置片段的 ID 然而 有一个String tag您可以在 Frag
  • 在 NodeJS 中从上传的文件中读取缓冲区数据

    我正在使用 express 模块上传文件 我必须使用读取上传图像的 EXIF 数据节点 exif 我不想将文件存储在磁盘上 并且上述模块支持从缓冲区读取 EXIF 数据 我需要从上传的图像中读取缓冲区数据 这是上传代码 var expres
  • 是否可以将 Google Apps 脚本 Web 应用程序发布到 G Suite Marketplace?

    我知道可以将 Google 脚本 Web 应用程序发布到 Chrome 网上应用店 但也可以在 Google Suite Marketplace 中发布吗 GAS 编辑器中没有 发布到市场 选项 但我查看了 Chrome Web Store
  • Kafka Log 压缩返回具有相同键的两条记录

    我在卡夫卡中的日志压缩有一个奇怪的行为 我创建了一个具有以下配置的主题 kafka topics zookeeper create topic myTopic partitions 12 replication factor 3 confi
  • 如何使用 cx_oracle 执行 SQL 脚本

    我正在尝试在 Oracle 数据库上执行 SQL 脚本 从文件中读取 我尝试了很多方法 但没有一个有效 我有以下方法 def connect cx oracle dns tns cx Oracle makedsn config DB HOS
  • PowerShell 中的高级过滤器

    我正在尝试通过 PowerShell 使用 Excel 高级过滤器 但我没有任何运气 我可以通过运行以下代码成功使用自动过滤器 rangetofilter worksheet2 usedrange select excel selectio
  • 在Python2.7中实现Barrier

    我使用 Barriers 在 Python3 中实现了这段代码 我想在 Python2 7 中获得相同的功能 但我不知道要使用哪个同步原语 因为 Python2 7 中不存在屏障 import threading import time f
  • 可以将其当前计数减少 N (N>=1) 的信号量?

    我正在实现一个流量控制组件 限制可以发送的最大请求 每个工作线程可以发送单个请求或一批请求 但任何时候待处理请求的总数都不应超过最大数量 我最初想用 SemaphoreSlim 来实现 将信号量初始化为最大请求计数 然后当工作线程要调用服务