使用 SemaphoreSlim 限制并行任务的数量 - 为什么它有效? [英] Limiting the number of parallel task with SemaphoreSlim - why does it work?

查看:27
本文介绍了使用 SemaphoreSlim 限制并行任务的数量 - 为什么它有效?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 MS Docu 中,您可以阅读有关 SemaphoreSlim 的信息:„代表了信号量的轻量级替代方案,它限制了可以同时访问资源或资源池的线程数量.
https://docs.microsoft.com/en-us/dotnet/api/system.threading.semaphoreslim?view=net-5.0

in MS Docu you can read about SemaphoreSlim: „Represents a lightweight alternative to Semaphore that limits the number of threads that can access a resource or pool of resources concurrently."
https://docs.microsoft.com/en-us/dotnet/api/system.threading.semaphoreslim?view=net-5.0

在我的理解中,Task 不同于 Thread.任务级别高于线程.不同的任务可以在同一个线程上运行.或者一个任务可以在另一个线程上继续,而不是在它开始时.
(比较:使用异步的 .NET 中的服务器端应用程序将使用很少的线程,而不会限制自己.如果真的可以由单个线程提供服务,那很可能是 - 如果您永远不会有不止一件事情要做在物理处理方面做,那很好."来自 在 C# 中如何运行方法异步在同一个线程中)

In my understanding a Task is different from Thread. Task is higher level than Thread. Different tasks can run on the same thread. Or a task can be continued on another thread than it was started on.
(Compare: "server-side applications in .NET using asynchrony will use very few threads without limiting themselves to that. If everything really can be served by a single thread, it may well be - if you never have more than one thing to do in terms of physical processing, then that's fine." from in C# how to run method async in the same thread)

IMO 如果你把这些信息放在一起,结论是你不能限制并行运行的任务数量与使用信号量 slim,但是......

IMO if you put this information together, the conclusion is that you can’t limit the number of Tasks running in parallel with the use of a semaphore slim, but…

  • 还有其他文本给出了这种建议(如何限制并发异步 I/O 操作的数量?,请参阅您绝对可以做到这一点……")
  • 如果我在我的机器上执行这段代码,这似乎是可能的.如果我使用不同的 _MaxDegreeOfParallelism 数字和不同的数字范围,_RunningTasksCount 不会超过 MaxDegreeOfParallelism 给出的限制.
  • there are other texts that give this kind of advice (How to limit the amount of concurrent async I/O operations?, see "You can definitely do this…")
  • if I’m executing this code on my machine it seems it IS possible. If I work with different numbers for _MaxDegreeOfParallelism and different ranges of numbers, _RunningTasksCount doesn’t exceed the limit that is given by MaxDegreeOfParallelism.

有人能给我提供一些信息来澄清吗?

Can somebody provide me some information to clearify?

   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;
        }        
    }

推荐答案

代表信号量的轻量级替代方案,它限制可以并发访问资源或资源池的线程数.

Represents a lightweight alternative to Semaphore that limits the number of threads that can access a resource or pool of resources concurrently.

好吧,当 SemaphoreSlim 首次被引入时,这是一个完美的描述——它只是一个轻量级的 Semaphore.从那时起,它获得了新方法(即 WaitAsync),使其能够像 异步 同步原语一样工作.

Well, that was a perfectly fine description when SemaphoreSlim was first introduced - it was just a lightweight Semaphore. Since that time, it has gotten new methods (i.e., WaitAsync) that enable it to act like an asynchronous synchronization primitive.

在我的理解中,Task 不同于 Thread.任务级别高于线程.不同的任务可以在同一个线程上运行.或者一个任务可以在另一个线程上继续,而不是在它开始时.

In my understanding a Task is different from Thread. Task is higher level than Thread. Different tasks can run on the same thread. Or a task can be continued on another thread than it was started on.

这适用于我所说的委托任务".还有一个完全不同 类型的任务,我称之为承诺任务".Promise 任务类似于其他语言(例如 JavaScript)中的 promises(或futures")),它们只是代表某个事件的完成.Promise 任务不会运行"任何地方;它们只是根据某个未来事件(通常通过回调)完成.

This is true for what I call "Delegate Tasks". There's also a completely different kind of Task that I call "Promise Tasks". Promise tasks are similar to promises (or "futures") in other languages (e.g., JavaScript), and they just represent the completion of some event. Promise tasks do not "run" anywhere; they just complete based on some future event (usually via a callback).

async 方法总是返回承诺任务.异步方法中的代码实际上并不是作为任务的一部分运行的;任务本身只代表async 方法的完成.我推荐我的 async intro 以了解有关 的更多信息异步以及代码部分的调度方式.

async methods always return promise tasks. The code in an asynchronous method is not actually run as part of the task; the task itself only represents the completion of the async method. I recommend my async intro for more information about async and how the code portions are scheduled.

如果你把这些信息放在一起,结论是你不能通过使用信号量 slim 来限制并行运行的任务数量

if you put this information together, the conclusion is that you can’t limit the number of Tasks running in parallel with the use of a semaphore slim

这是个人喜好,但我尽量对术语非常小心,正是为了避免这样的问题.委托任务可以并行运行,例如,Parallel.Promise 任务不会运行",也不会并行"运行,但是您可以有多个 并发 Promise 任务,它们都进行中.而 SemaphoreSlimWaitAsync 是限制这种并发性的完美匹配.

This is personal preference, but I try to be very careful about terminology, precisely to avoid problems like this question. Delegate tasks may run in parallel, e.g., Parallel. Promise tasks do not "run", and they don't run in "parallel", but you can have multiple concurrent promise tasks that are all in progress. And SemaphoreSlim's WaitAsync is a perfect match for limiting that kind of concurrency.

您可能希望阅读 Stephen Toub 的AsyncSemaphore(以及该系列的其他文章).它与 SemaphoreSlim 的实现不同,但就承诺任务而言,其行为基本相同.

You may wish to read about Stephen Toub's AsyncSemaphore (and other articles in that series). It's not the same implementation as SemaphoreSlim, but behaves essentially the same as far as promise tasks are concerned.

这篇关于使用 SemaphoreSlim 限制并行任务的数量 - 为什么它有效?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆