信号量动态调整大小 C#

发布于 2024-10-31 09:50:25 字数 132 浏览 3 评论 0原文

我试图使用信号量来控制可以同时运行的作业实例的数量。虽然这对于等待方法来说相当简单,但我还希望该值可以在运行时配置,以便我可以向上或向下增加计数。

我意识到倒计时可能会出现问题,但有没有办法真正做到这一点?这是使用信号量的正确方法吗?

I'm trying to use semaphores to control how many instances of a job can be run at the same time. While this is fairly simple with a wait method, I also want the value to be configurable at runtime so that I can bump the count up or down.

I realize that there may be issues bumping the count down but is there a way to actually do this? Is this the right approach to be using semaphores?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

海夕 2024-11-07 09:50:25

根据 ReleaseSemaphore 的文档,对于 lReleaseCount 参数:

信号量对象当前计数要增加的量。该值必须大于零。 如果指定的数量会导致信号量的计数超过创建信号量时指定的最大计数,则计数不会更改并且函数返回 FALSE。

这和其他文档表明信号量对于您的限制来说不是正确的选择。信号量一旦创建,就会有一个硬性最大值,如果不重新创建信号量就无法更改该最大值。换句话说,它不是一个可以更改的动态值

在这种情况下,您需要找到另一种方法来管理您的限制。

使用信号量的一种方法是分配一个足够大的信号量来满足所有未来的需求,然后获取足够的“实例”以减少可用的信号量数量回到您目前需要的数量。当您想要增加可用实例的数量时,只需释放您一开始就获取的一些实例即可。

但是,我质疑你为什么要这样做。真正决定你可以同时执行多少个作业的限制因素是什么?信号量很可能不是这个问题的正确答案。

According to the documentation of ReleaseSemaphore, for the lReleaseCount parameter:

The amount by which the semaphore object's current count is to be increased. The value must be greater than zero. If the specified amount would cause the semaphore's count to exceed the maximum count that was specified when the semaphore was created, the count is not changed and the function returns FALSE.

This, and other documentation suggests that a semaphore is not the right choice for your limitation. A semaphore, once created, has a hard maximum that cannot be changed without recreating the semaphore. In other words, it is not a dynamic value that can be changed.

You need to find another way of managing your limit in this scenario.

One way you could use a semaphore would be to allocate a semaphore that is big enough for all future needs, and then just grab enough "instances" of it to reduce the available number back down to what you need at the moment. When you want to increase the number of available instances, just release some of those you grabbed at the beginning.

However, I question why you want to do this. What is the limiting factor that really decides how many jobs you can execute at the same time here? Most likely a semaphore is not the right answer to this.

我为君王 2024-11-07 09:50:25

虽然使用等待方法相当简单,但我还希望该值可以在运行时配置,以便我可以向上或向下增加计数。

我不建议为此使用信号量。

如果您使用 .NET 4,我建议的方法是创建一个自定义 TaskScheduler 允许您在运行时更改并发级别。然后,您可以使用在选项中传递此 TaskScheduler 的单个 Parallel.For/ForEach 调用来运行整个操作,并在运行时更改并发级别。

这将使处理向上或向下移动级别变得相当容易。当级别上升时,您只需根据需要添加新线程即可。当它们出现故障时,只需从内部集合中删除该线程(但不要停止它),并让它完成当前的工作。这将允许您根据需要进行扩展。

While this is fairly simple with a wait method, I also want the value to be configurable at runtime so that I can bump the count up or down.

I would not recommend using semaphores for this.

If you're in .NET 4, my suggested method would be to create a custom TaskScheduler which would allow you to change the level of concurrency at runtime. You could then run your entire operation using a single Parallel.For/ForEach call passing this TaskScheduler in the options, and change the level of concurrency at runtime.

This would make it fairly easy to handle moving levels up or down. When levels go up, you just add new threads as needed. When they go down, just remove that thread from your internal collection (but don't stop it), and let it finish its current work. This would allow you to scale as needed.

送你一个梦 2024-11-07 09:50:25

根据Lasse V. Karlsen的建议,我在kotlin中实现了一个动态信号量。我不知道如何在 C# 中做到这一点,但应该相当相似。只需将其视为伪代码答案即可。

该代码具有以下行为:

  • 您可以创建信号量,如果您从不更新它,它将完全像信号量一样工作

  • 增加许可证将释放许可证最多 100 个(随意增加最大值)

  • 当仍有大量许可证时减少许可证是即时的

  • 当当前发放的许可证多于新的允许限制时减少许可证最终将减少许可证,从而允许进程自行完成。在达到目标许可证之前不会发放新许可证

     const val maximalSize = 100
    
      私有 val DynamicSemaphoreSingleton = DynamicSemaphore(maximalSize)
    
      fun getDynamicSemaphoreSingleton(允许:Int):DynamicSemaphore {
          返回 DynamicSemaphoreSingleton.also { it.updatePermits(permits) }
      }
    
      类 DynamicSemaphore(private var 允许: Int) : 信号量 {
          private val backingSemaphore = Semaphore(maximalSize, maximalSize - 允许)
    
          私有变量 extraAcquires = 0
    
          有趣的 updatePermits(newPermits: Int) {
              val 差异 = newPermits - 许可
    
              如果(差值<0){
                  val numberOfFailedAcquires =
                      List(-difference) { backingSemaphore.tryAcquire() }.count { it.not() }
    
                  同步(this) { extraAcquires += numberOfFailedAcquires }
              } 别的 {
                  重复(差异) { backingSemaphore.release() }
              }
              许可证 = 新许可证
          }
    
          覆盖 val availablePermits: Int
              get() = backingSemaphore.availablePermits
    
          覆盖挂起乐趣获取(){
              backingSemaphore.acquire()
          }
    
          覆盖 funrelease() {
              同步(这个){
                  if (extraAcquires > 0) {
                      额外获得——
                  } 别的 {
                      backingSemaphore.release()
                  }
              }
          }
    
          重写 fun tryAcquire(): Boolean {
              返回 backingSemaphore.tryAcquire()
          }
      }
    

Based on the suggestion of Lasse V. Karlsen I implemented a dynamic semaphore in kotlin. I do not know how to do it in C#, but should be fairly similar. Just consider this a pseudo code answer.

The code has the following behaviour:

  • you can create the semphaphore and it will act exactly like a semamphore if you never update it

  • increasing the permits will release permits up to 100 (feel free to increase the maximum)

  • decreasing the permits when there are still plenty permits left is instant

  • decreasing the permits when there are more currently handed out the permits than the new allowed limit will eventually decrease the permits allowing processes to finish on their own. New permits are not handed out until the target permits have been reached

      const val maximalSize = 100
    
      private val DynamicSemaphoreSingleton = DynamicSemaphore(maximalSize)
    
      fun getDynamicSemaphoreSingleton(permits: Int): DynamicSemaphore {
          return DynamicSemaphoreSingleton.also { it.updatePermits(permits) }
      }
    
      class DynamicSemaphore(private var permits: Int) : Semaphore {
          private val backingSemaphore = Semaphore(maximalSize, maximalSize - permits)
    
          private var extraAcquires = 0
    
          fun updatePermits(newPermits: Int) {
              val difference = newPermits - permits
    
              if (difference < 0) {
                  val numberOfFailedAcquires =
                      List(-difference) { backingSemaphore.tryAcquire() }.count { it.not() }
    
                  synchronized(this) { extraAcquires += numberOfFailedAcquires }
              } else {
                  repeat(difference) { backingSemaphore.release() }
              }
              permits = newPermits
          }
    
          override val availablePermits: Int
              get() = backingSemaphore.availablePermits
    
          override suspend fun acquire() {
              backingSemaphore.acquire()
          }
    
          override fun release() {
              synchronized(this) {
                  if (extraAcquires > 0) {
                      extraAcquires--
                  } else {
                      backingSemaphore.release()
                  }
              }
          }
    
          override fun tryAcquire(): Boolean {
              return backingSemaphore.tryAcquire()
          }
      }
    
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文