信号量 - 初始计数有什么用?

发布于 2024-10-12 14:08:36 字数 894 浏览 2 评论 0原文

http://msdn.microsoft.com/en-us/library /system.threading.semaphoreslim.aspx

要创建信号量,我需要提供初始计数和最大计数。 MSDN 指出初始计数是 -

初始请求数 可以授予的信号量 同时。

虽然它指出最大计数是

最大请求数 可以授予的信号量 同时。

我可以理解最大计数就是可以并发访问某个资源的最大线程数,但是初始计数有什么用呢?

如果我创建一个初始计数为 0、最大计数为 2 的信号量,则我的线程池线程都无法访问该资源。如果我将初始计数设置为 1,最大计数设置为 2,则只有一个线程池线程可以访问该资源。只有当我将初始计数和最大计数都设置为 2 时,2 个线程才能同时访问资源。那么,我真的对初始计数的意义感到困惑吗?

SemaphoreSlim semaphoreSlim = new SemaphoreSlim(0, 2); //all threadpool threads wait
SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1, 2);//only one thread has access to the resource at a time
SemaphoreSlim semaphoreSlim = new SemaphoreSlim(2, 2);//two threadpool threads can access the resource concurrently

http://msdn.microsoft.com/en-us/library/system.threading.semaphoreslim.aspx

To create a semaphore, I need to provide an initial count and maximum count. MSDN states that an initial count is -

The initial number of requests for the
semaphore that can be granted
concurrently.

While it states that maximum count is

The maximum number of requests for the
semaphore that can be granted
concurrently.

I can understand that the maximum count is the maximum number of threads that can access a resource concurrently, but what is the use of initial count?

If I create a semaphore with an initial count of 0 and a maximum count of 2, none of my threadpool threads are able to access the resource. If I set the initial count as 1 and maximum count as 2 then only one thread pool thread can access the resource. It is only when I set both initial count and maximum count as 2, 2 threads are able to access the resource concurrently. So, I am really confused about the significance of initial count?

SemaphoreSlim semaphoreSlim = new SemaphoreSlim(0, 2); //all threadpool threads wait
SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1, 2);//only one thread has access to the resource at a time
SemaphoreSlim semaphoreSlim = new SemaphoreSlim(2, 2);//two threadpool threads can access the resource concurrently

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

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

发布评论

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

评论(11

懒猫 2024-10-19 14:08:36

所以,我真的对初始计数的意义感到困惑?

此处可能有帮助的重要一点是,Wait 会减少信号量计数,而 Release 则会增加信号量计数。

initialCount 是立即允许的资源访问次数。或者,换句话说,它是在信号量实例化后可以立即调用 Wait 而不会发生阻塞的次数。

maximumCount 是信号量可以获得的最高计数。它是在假设 initialCount 计数为零的情况下可以调用 Release 而不会引发异常的次数。如果 initialCount 设置为与 maximumCount 相同的值,则在实例化信号量后立即调用 Release 将引发异常。

So, I am really confused about the significance of initial count?

One important point that may help here is that Wait decrements the semaphore count and Release increments it.

initialCount is the number of resource accesses that will be allowed immediately. Or, in other words, it is the number of times Wait can be called without blocking immediately after the semaphore was instantiated.

maximumCount is the highest count the semaphore can obtain. It is the number of times Release can be called without throwing an exception assuming initialCount count was zero. If initialCount is set to the same value as maximumCount then calling Release immediately after the semaphore was instantiated will throw an exception.

嗫嚅 2024-10-19 14:08:36

是的,当初始数字设置为 0 时 - 当您递增“CurrentCount”属性时,所有线程都将等待。您可以使用 Release() 或 Release(Int32) 来完成此操作。

Release(...) - 将增加信号量计数器

Wait(...) - 将减少

它 计数器(“CurrentCount”属性)的增量不能大于您在初始化中设置的最大计数。

例如:

SemaphoreSlim^ s = gcnew SemaphoreSlim(0,2); //s->CurrentCount = 0
s->Release(2); //s->CurrentCount = 2
...

s->Wait(); //Ok. s->CurrentCount = 1
...

s->Wait(); //Ok. s->CurrentCount = 0
...

s->Wait(); //Will be blocked until any of the threads calls Release()

Yes, when the initial number sets to 0 - all threads will be waiting while you increment the "CurrentCount" property. You can do it with Release() or Release(Int32).

Release(...) - will increment the semaphore counter

Wait(...) - will decrement it

You can't increment the counter ("CurrentCount" property) greater than maximum count which you set in initialization.

For example:

SemaphoreSlim^ s = gcnew SemaphoreSlim(0,2); //s->CurrentCount = 0
s->Release(2); //s->CurrentCount = 2
...

s->Wait(); //Ok. s->CurrentCount = 1
...

s->Wait(); //Ok. s->CurrentCount = 0
...

s->Wait(); //Will be blocked until any of the threads calls Release()
顾挽 2024-10-19 14:08:36

您希望有多少个线程能够同时访问资源?将您的初始计数设置为该数字。如果该数字在程序的整个生命周期中永远不会增加,请将最大计数也设置为该数字。这样,如果您在释放资源的方式上出现编程错误,您的程序将崩溃并通知您。

(有两种构造函数:一种仅采用初始值,另一种还采用最大计数。使用合适的一种。)

How many threads do you want to be able to access resource at once? Set your initial count to that number. If that number is never going to increase throughout the life of the program, set your max count to that number too. That way, if you have a programming error in how you release the resource, your program will crash and let you know.

(There are two constructors: one that takes only an initial value, and one that additionally takes the max count. Use whichever is appropriate.)

迷途知返 2024-10-19 14:08:36

通常,当 SemaphoreSlim 用作节流阀,initialCountmaxCount 具有相同的值:

SemaphoreSlim semaphore = new(maximumConcurrency, maximumConcurrency);

...并且 semaphore 与此模式一起使用:

await semaphore.WaitAsync(); // or semaphore.Wait();
try
{
    // Invoke the operation that must be throttled
}
finally
{
    semaphore.Release();
}

initialCount 配置最大并发策略,maxCount 确保不会违反此策略。如果省略第二个参数(maxCount),只要代码中没有错误,您的代码也将正常工作。如果存在错误,并且每个 WaitAsync 后面可能有多个 Release,则 maxCount 将有助于在该错误发生之前检测到该错误最终出现在程序的发布版本中。该错误将显示为 SemaphoreFullException,希望在预发布版本的测试期间,这样您就能够在它造成任何真正危害之前(在它导致违反生产中的最大并发策略之前)跟踪并消除它环境)。

maxCount 参数的默认值(如果您省略它)为 Int32.MaxValue (源代码)。

Normally, when the SemaphoreSlim is used as a throttler, both initialCount and maxCount have the same value:

SemaphoreSlim semaphore = new(maximumConcurrency, maximumConcurrency);

...and the semaphore is used with this pattern:

await semaphore.WaitAsync(); // or semaphore.Wait();
try
{
    // Invoke the operation that must be throttled
}
finally
{
    semaphore.Release();
}

The initialCount configures the maximum concurrency policy, and the maxCount ensures that this policy will not be violated. If you omit the second argument (the maxCount) your code will work just as well, provided that there are no bugs in it. If there is a bug, and each WaitAsync could be followed by more than one Release, then the maxCount will help at detecting this bug before it ends up in the released version of your program. The bug will be surfaced as a SemaphoreFullException, hopefully during the testing of a pre-release version, and so you'll be able to track and eliminate it before it does any real harm (before it has caused the violation of the maximum concurrency policy in a production environment).

The default value of the maxCount argument, in case you omit it, is Int32.MaxValue (source code).

南渊 2024-10-19 14:08:36

如果您希望一段时间内没有线程访问您的资源,则可以将初始计数传递为 0,并且当您希望在创建信号量后立即授予对所有线程的访问权限时,可以传递等于最大计数的初始计数值。例如:

hSemaphore = CreateSemaphoreA(NULL, 0, MAX_COUNT, NULL) ;

//Do something here
//No threads can access your resource

ReleaseSemaphore(hSemaphore, MAX_COUNT, 0) ;

//All threads can access the resource now

正如 MSDN 文档中所引用的 - “ReleaseSemaphore 的另一个用途是在应用程序的初始化期间。应用程序可以创建初始计数为零的信号量。这会将信号量的状态设置为无信号,并阻止所有线程访问受保护的资源。当应用程序完成初始化时,它使用 ReleaseSemaphore 将计数增加到最大值,以允许正常访问受保护的资源。”

If you wish that no thread should access your resource for some time, you pass the initial count as 0 and when you wish to grant the access to all of them just after creating the semaphore, you pass the value of initial count equal to maximum count. For example:

hSemaphore = CreateSemaphoreA(NULL, 0, MAX_COUNT, NULL) ;

//Do something here
//No threads can access your resource

ReleaseSemaphore(hSemaphore, MAX_COUNT, 0) ;

//All threads can access the resource now

As quoted in MSDN Documentation- "Another use of ReleaseSemaphore is during an application's initialization. The application can create a semaphore with an initial count of zero. This sets the semaphore's state to nonsignaled and blocks all threads from accessing the protected resource. When the application finishes its initialization, it uses ReleaseSemaphore to increase the count to its maximum value, to permit normal access to the protected resource."

云淡风轻 2024-10-19 14:08:36

可以这样想:

  • initialCount是“并行度”(可以进入的线程数)
  • maxCount确保你不会释放 超出您应有的范围

例如,假设您希望并发度为“1”(一次仅执行一个操作)。但是由于代码中的一些错误,您释放了信号量两次。所以现在你有两个并发了!

但如果你设置了 maxCount - 它不会允许这样做并抛出异常。

Think of it like this:

  • initialCount is the "degree of parallelism" (number of threads that can enter)
  • maxCount ensures that you don't Release more than you should

For example, say you want a concurrency degree of "1" (only one operation at a time). But then due to some bug in your code, you release the semaphore twice. So now you have a concurrency of two!

But if you set maxCount - it will not allow this and throw an exception.

用心笑 2024-10-19 14:08:36

这样,当当前线程创建信号量时,它可以从一开始就声明一些资源。

This way when the current thread creates the semaphore it could claim some resources from the start.

不乱于心 2024-10-19 14:08:36

maxCount 是您将允许的并发线程数。

然而,当你开始限制时,你可能已经知道有一些活动线程,所以你想告诉它“嘿,我想要 6 个并发线程,但我已经有 4 个了,所以我希望你只现在还允许 2 个”,因此您需要将 initialCount 设置为 2,将 maxCount 设置为 6。

SemaphoreSlim 中 initialCount 的限制 的一点是它不能是负数,所以你不能说“嘿,我想要最多 6 个并发线程,但我目前有 10 个,所以先释放 5 个线程,然后再允许另一个线程进入。 ”。这意味着 initialCount 为 -4。为此,您需要使用第 3 方包,例如 SemaphoreSlimThrotdling (请注意,我是SemaphoreSlimThrotdling 的作者)。

maxCount is the number of concurrent threads that you're going to be allowing.

However, when you start the throttling, you may already know there are a few active threads, so you'd want to tell it "hey, I want to have 6 concurrent threads, but I already have 4, so I want you to only allow 2 more for now", so you'd set initialCount to 2 and maxCount to 6.

The limitation with initialCount in SemaphoreSlim is that it cannot be a negative number, so you can't say "hey, I want to have up to 6 concurrent threads, but I currently have 10, so let 5 get released before you allow another one in.". That would mean an initialCount of -4. For that you'd need to use a 3rd party package like SemaphoreSlimThrottling (note that I am the author of SemaphoreSlimThrottling).

愁以何悠 2024-10-19 14:08:36

发布我自己的解释,因为每次我回到这个线程(现在很多次),我都需要很长时间才能理解。

  1. 信号量有一个内部 m_currentCount 值。简称为Count
  2. initialCount顾名思义,就是Count的初始值。
  3. 调用 .Wait() 等待 Count 大于零,然后将其递减。
  4. 调用 .Release()Count 添加 1。 .Release(x) 也由于某种原因存在,它将 x 添加到 Count 中。

那么 maxCount 有什么用呢?它所做的只是建立一个约束。如果信号量的 Count 变得高于 maxCount,则信号量将引发异常。这可以在测试时使用,以确保每个 .Wait() 与一个 .Release() 恰好配对。

默认情况下,maxCountint.MaxValue,有效禁用约束。

最佳实践我认为,始终为initialCountmaxCount创建具有相同值的SemaphoreSlim

Posting my own explanation because every time I come back to this thread (many times now) it takes me way too long to understand.

  1. The semaphore has an internal m_currentCount value. Call it Count for short.
  2. initialCount as its name suggests, is the initial value of Count.
  3. Calling .Wait() waits for Count to be higher than zero, then decrements it.
  4. Calling .Release() adds one to Count. .Release(x) also exists for some reason, which adds x to Count.

So what's maxCount for? All it does is establish a constraint. The semaphore will throw an exception if its Count ever becomes higher than maxCount. This can be used while testing to ensure that every single .Wait() is paired with exactly one .Release().

maxCount is int.MaxValue by default, effectively disabling the constraint.

Best practice I think, is to always create the SemaphoreSlim with the same value for both initialCount and maxCount.

我的鱼塘能养鲲 2024-10-19 14:08:36

正如 MSDN 在备注下解释的那样部分:

如果initialCount小于maximumCount,则效果与当前线程调用WaitOne(maximumCount减去initialCount)次相同。如果您不想为创建信号量的线程保留任何条目,请对maximumCount 和initialCount 使用相同的数字。

因此,如果初始计数为 0,最大值为 2,就好像 WaitOne 已被主线程调用两次,因此我们已达到容量(信号量计数现在为 0),并且没有线程可以进入信号量。类似地,如果初始计数为 1 并且最大值为 2,则 WaitOnce 已被调用一次,并且在再次达到容量之前只有一个线程可以进入,依此类推。

如果初始计数使用 0,我们始终可以调用 Release(2) 将信号量计数增加到最大值,以允许最大数量的线程获取资源。

As MSDN explains it under the Remarks section:

If initialCount is less than maximumCount, the effect is the same as if the current thread had called WaitOne (maximumCount minus initialCount) times. If you do not want to reserve any entries for the thread that creates the semaphore, use the same number for maximumCount and initialCount.

So If the initial count is 0 and max is 2 it is as if WaitOne has been called twice by the main thread so we have reached capacity (semaphore count is 0 now) and no thread can enter Semaphore. Similarly If initial count is 1 and max is 2 WaitOnce has been called once and only one thread can enter before we reach capacity again and so on.

If 0 is used for initial count we can always call Release(2) to increase the semaphore count to max to allow maximum number of threads to acquire resource.

奈何桥上唱咆哮 2024-10-19 14:08:36

信号量可用于保护资源池。我们使用资源池来重用创建成本较高的东西 - 例如数据库连接。

所以初始计数是指池中可用资源的数量
某个进程的开始。当您阅读代码中的 initialCount 时,您应该考虑您在创建此资源池时投入了多少前期工作。

我真的很困惑初始计数的意义?

初始计数 = 前期成本

因此,根据应用程序的使用情况,此值可能会对应用程序的性能产生巨大影响。这不仅仅是一些任意数字。

您应该仔细考虑您要创建的内容、创建它们的成本以及您立即需要的数量。您实际上应该能够绘制此参数的最佳值,并且应该考虑将其配置为可配置,以便您可以根据执行时的情况调整流程的性能。

Semaphores can be used to protect a pool of resources. We use resource pools to reuse things that are expensive to create - such as database connections.

So initial count refers to the number of available resources in the pool at the
start of some process. When you read the initialCount in code you should be thinking in terms of how much up front effort are you putting into creating this pool of resources.

I am really confused about the significance of initial count?

Initial count = Upfront cost

As such, depending on the usage profile of your application, this value can have a dramatic effect on the performance of your application. It's not just some arbitrary number.

You should think carefully about what you creating, how expensive they are to create and how many you need right away. You should literally able able to graph the optimal value for this parameter and should likely think about making it configurable so you can adapt the performance of the process to the time at which it is being executed.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文