信号量 - 初始计数有什么用?
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
此处可能有帮助的重要一点是,
Wait
会减少信号量计数,而Release
则会增加信号量计数。initialCount
是立即允许的资源访问次数。或者,换句话说,它是在信号量实例化后可以立即调用Wait
而不会发生阻塞的次数。maximumCount
是信号量可以获得的最高计数。它是在假设initialCount
计数为零的情况下可以调用Release
而不会引发异常的次数。如果initialCount
设置为与maximumCount
相同的值,则在实例化信号量后立即调用Release
将引发异常。One important point that may help here is that
Wait
decrements the semaphore count andRelease
increments it.initialCount
is the number of resource accesses that will be allowed immediately. Or, in other words, it is the number of timesWait
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 timesRelease
can be called without throwing an exception assuminginitialCount
count was zero. IfinitialCount
is set to the same value asmaximumCount
then callingRelease
immediately after the semaphore was instantiated will throw an exception.是的,当初始数字设置为 0 时 - 当您递增“CurrentCount”属性时,所有线程都将等待。您可以使用 Release() 或 Release(Int32) 来完成此操作。
Release(...) - 将增加信号量计数器
Wait(...) - 将减少
它 计数器(“CurrentCount”属性)的增量不能大于您在初始化中设置的最大计数。
例如:
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:
您希望有多少个线程能够同时访问资源?将您的初始计数设置为该数字。如果该数字在程序的整个生命周期中永远不会增加,请将最大计数也设置为该数字。这样,如果您在释放资源的方式上出现编程错误,您的程序将崩溃并通知您。
(有两种构造函数:一种仅采用初始值,另一种还采用最大计数。使用合适的一种。)
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.)
通常,当
SemaphoreSlim
用作节流阀,initialCount
和maxCount
具有相同的值:...并且
semaphore
与此模式一起使用:initialCount
配置最大并发策略,maxCount
确保不会违反此策略。如果省略第二个参数(maxCount
),只要代码中没有错误,您的代码也将正常工作。如果存在错误,并且每个WaitAsync
后面可能有多个Release
,则maxCount
将有助于在该错误发生之前检测到该错误最终出现在程序的发布版本中。该错误将显示为SemaphoreFullException
,希望在预发布版本的测试期间,这样您就能够在它造成任何真正危害之前(在它导致违反生产中的最大并发策略之前)跟踪并消除它环境)。maxCount
参数的默认值(如果您省略它)为Int32.MaxValue
(源代码)。Normally, when the
SemaphoreSlim
is used as a throttler, bothinitialCount
andmaxCount
have the same value:...and the
semaphore
is used with this pattern:The
initialCount
configures the maximum concurrency policy, and themaxCount
ensures that this policy will not be violated. If you omit the second argument (themaxCount
) your code will work just as well, provided that there are no bugs in it. If there is a bug, and eachWaitAsync
could be followed by more than oneRelease
, then themaxCount
will help at detecting this bug before it ends up in the released version of your program. The bug will be surfaced as aSemaphoreFullException
, 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, isInt32.MaxValue
(source code).如果您希望一段时间内没有线程访问您的资源,则可以将初始计数传递为 0,并且当您希望在创建信号量后立即授予对所有线程的访问权限时,可以传递等于最大计数的初始计数值。例如:
正如 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:
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."
可以这样想:
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'tRelease
more than you shouldFor 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.这样,当当前线程创建信号量时,它可以从一开始就声明一些资源。
This way when the current thread creates the semaphore it could claim some resources from the start.
maxCount
是您将允许的并发线程数。然而,当你开始限制时,你可能已经知道有一些活动线程,所以你想告诉它“嘿,我想要 6 个并发线程,但我已经有 4 个了,所以我希望你只现在还允许 2 个”,因此您需要将
initialCount
设置为 2,将maxCount
设置为 6。SemaphoreSlim 中
的一点是它不能是负数,所以你不能说“嘿,我想要最多 6 个并发线程,但我目前有 10 个,所以先释放 5 个线程,然后再允许另一个线程进入。 ”。这意味着initialCount
的限制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 andmaxCount
to 6.The limitation with
initialCount
inSemaphoreSlim
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 aninitialCount
of -4. For that you'd need to use a 3rd party package like SemaphoreSlimThrottling (note that I am the author of SemaphoreSlimThrottling).发布我自己的解释,因为每次我回到这个线程(现在很多次),我都需要很长时间才能理解。
m_currentCount
值。简称为Count
。initialCount
顾名思义,就是Count
的初始值。.Wait()
等待Count
大于零,然后将其递减。.Release()
为Count
添加 1。.Release(x)
也由于某种原因存在,它将x
添加到Count
中。那么
maxCount
有什么用呢?它所做的只是建立一个约束。如果信号量的Count
变得高于maxCount
,则信号量将引发异常。这可以在测试时使用,以确保每个.Wait()
与一个.Release()
恰好配对。默认情况下,
maxCount
为int.MaxValue
,有效禁用约束。最佳实践我认为,始终为
initialCount
和maxCount
创建具有相同值的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.
m_currentCount
value. Call itCount
for short.initialCount
as its name suggests, is the initial value ofCount
..Wait()
waits forCount
to be higher than zero, then decrements it..Release()
adds one toCount
..Release(x)
also exists for some reason, which addsx
toCount
.So what's
maxCount
for? All it does is establish a constraint. The semaphore will throw an exception if itsCount
ever becomes higher thanmaxCount
. This can be used while testing to ensure that every single.Wait()
is paired with exactly one.Release()
.maxCount
isint.MaxValue
by default, effectively disabling the constraint.Best practice I think, is to always create the
SemaphoreSlim
with the same value for bothinitialCount
andmaxCount
.正如 MSDN 在备注下解释的那样部分:
因此,如果初始计数为 0,最大值为 2,就好像 WaitOne 已被主线程调用两次,因此我们已达到容量(信号量计数现在为 0),并且没有线程可以进入信号量。类似地,如果初始计数为 1 并且最大值为 2,则 WaitOnce 已被调用一次,并且在再次达到容量之前只有一个线程可以进入,依此类推。
如果初始计数使用 0,我们始终可以调用 Release(2) 将信号量计数增加到最大值,以允许最大数量的线程获取资源。
As MSDN explains it under the Remarks section:
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.
信号量可用于保护资源池。我们使用资源池来重用创建成本较高的东西 - 例如数据库连接。
所以初始计数是指池中可用资源的数量
某个进程的开始。当您阅读代码中的
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.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.