【发布时间】:2021-03-15 09:16:28
【问题描述】:
在 MS Docu 中,您可以阅读有关 SemaphoreSlim 的信息:
“代表 Semaphore 的轻量级替代方案,它限制了可以同时访问资源或资源池的线程数。”
https://docs.microsoft.com/en-us/dotnet/api/system.threading.semaphoreslim?view=net-5.0
据我了解,Task 与 Thread 不同。任务比线程更高级别。不同的任务可以在同一个线程上运行。或者可以在另一个线程上继续执行任务。
(比较:“使用异步的 .NET 中的服务器端应用程序将使用很少的线程,而不会限制自己。如果真的所有事情都可以由单个线程提供服务,那么它很可能是 - 如果你从来没有超过一件事要做就物理处理而言,那很好。”
来自in C# how to run method async in the same thread)
如果你把这些信息放在一起,IMO 得出的结论是,你不能限制使用信号量 slim 并行运行的任务数量,但是……
- 还有其他文本给出了这种建议(How to limit the amount of concurrent async I/O operations?,请参阅“你绝对可以这样做……”)
- 如果我在我的机器上执行此代码,它似乎是可能的。如果我为 _MaxDegreeOfParallelism 使用不同的数字和不同的数字范围,_RunningTasksCount 不会超过 MaxDegreeOfParallelism 给出的限制。
有人可以提供一些信息来澄清吗?
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
IRunner runner = new RunnerSemaphore();
runner.Run();
Console.WriteLine("Hit any key to close...");
Console.ReadLine();
}
}
public class RunnerSemaphore : IRunner
{
private readonly SemaphoreSlim _ConcurrencySemaphore;
private List<int> _Numbers;
private int _MaxDegreeOfParallelism = 3;
private object _RunningTasksLock = new object();
private int _RunningTasksCount = 0;
public RunnerSemaphore()
{
_ConcurrencySemaphore = new SemaphoreSlim(_MaxDegreeOfParallelism);
_Numbers = _Numbers = Enumerable.Range(1, 100).ToList();
}
public void Run()
{
RunAsync().Wait();
}
private async Task RunAsync()
{
List<Task> allTasks = new List<Task>();
foreach (int number in _Numbers)
{
var task = Task.Run
(async () =>
{
await _ConcurrencySemaphore.WaitAsync();
bool isFast = number != 1;
int delay = isFast ? 200 : 10000;
Console.WriteLine($"Start Work {number}\tManagedThreadId {Thread.CurrentThread.ManagedThreadId}\tRunning {IncreaseTaskCount()} tasks");
await Task.Delay(delay).ConfigureAwait(false);
Console.WriteLine($"End Work {number}\tManagedThreadId {Thread.CurrentThread.ManagedThreadId}\tRunning {DecreaseTaskCount()} tasks");
})
.ContinueWith((t) =>
{
_ConcurrencySemaphore.Release();
});
allTasks.Add(task);
}
await Task.WhenAll(allTasks.ToArray());
}
private int IncreaseTaskCount()
{
int taskCount;
lock (_RunningTasksLock)
{
taskCount = ++ _RunningTasksCount;
}
return taskCount;
}
private int DecreaseTaskCount()
{
int taskCount;
lock (_RunningTasksLock)
{
taskCount = -- _RunningTasksCount;
}
return taskCount;
}
}
【问题讨论】:
-
我已多次阅读您的问题,但我不完全理解您关于为什么它不起作用的问题。
SemaphoreSlim的WaitAsync方法不会阻塞线程,它会暂停执行,然后在可能的情况下继续执行。 -
它基本上是一个上下文不敏感的计数器(无论是线程还是任务)。每次
Wait或WaitAsync时它都会递减,Release时递增。 -
致菲尔多:谢谢。这是我之前弄错的信息。我认为对 Wait 和 Release 的调用是上下文敏感的,并且绑定到调用线程。也许我把它和锁的工作方式混为一谈了,线程的身份,即获取锁,确实很重要。
-
是的,这正是我所怀疑的。如果你做一些可重入的事情,你可以很容易地测试行为。