C#。是否有用于自定义线程池的.NET类

C#。是否有用于自定义线程池的.NET类,c#,multithreading,threadpool,C#,Multithreading,Threadpool,我一直试图找到一个简单的自定义线程池有一段时间了,但找不到,所以写了一个快速的穷人线程池 问题: 是否有任何.NET类已经可以这样做了?(在多次尝试找到一个后,都找不到它,只有博客帖子上的自定义实现比这个复杂得多!) 当任务进入时,最好使用线程池上的轮询或启动操作来使用线程 您可以查看,它有几个任务调度器。具体来说,WorkStealingTaskScheduler 我记得我曾经对它进行过测试,托管世界中没有任何东西可以与.NET自己的线程池相比,至少在没有不安全代码的情况下是如此。NET的库存

我一直试图找到一个简单的自定义线程池有一段时间了,但找不到,所以写了一个快速的穷人线程池

问题

  • 是否有任何.NET类已经可以这样做了?(在多次尝试找到一个后,都找不到它,只有博客帖子上的自定义实现比这个复杂得多!)


  • 当任务进入时,最好使用线程池上的轮询或启动操作来使用线程 您可以查看,它有几个任务调度器。具体来说,
    WorkStealingTaskScheduler

    我记得我曾经对它进行过测试,托管世界中没有任何东西可以与.NET自己的线程池相比,至少在没有不安全代码的情况下是如此。NET的库存线程池有很多优化,我清楚地记得其中一个优化是在等待前处理一个工作项之后,积极地旋转工作项

    好的一面是,您可以非常接近它,但是模仿
    ThreadPool
    所做的是一项相当了不起的壮举。也就是说,如果你想这样做的话。我不想使用默认线程池的原因之一是,它的策略是在min.threads之后缓慢创建线程,但简单地增加min.threads通常就足够了


    问题是,除非您使用的是TPL,否则您可以提供自己的任务调度器,因为没有库存线程池接口,通常其他任何东西,尤其是遗留代码,都不会占用您的自定义线程池。不幸的是,
    ThreadPool
    是一个静态类这一事实进一步阻碍了其他线程池的使用。

    您可以看看,它有几个任务调度器。具体来说,
    WorkStealingTaskScheduler

    我记得我曾经对它进行过测试,托管世界中没有任何东西可以与.NET自己的线程池相比,至少在没有不安全代码的情况下是如此。NET的库存线程池有很多优化,我清楚地记得其中一个优化是在等待前处理一个工作项之后,积极地旋转工作项

    好的一面是,您可以非常接近它,但是模仿
    ThreadPool
    所做的是一项相当了不起的壮举。也就是说,如果你想这样做的话。我不想使用默认线程池的原因之一是,它的策略是在min.threads之后缓慢创建线程,但简单地增加min.threads通常就足够了


    问题是,除非您使用的是TPL,否则您可以提供自己的任务调度器,因为没有库存线程池接口,通常其他任何东西,尤其是遗留代码,都不会占用您的自定义线程池。不幸的是,
    ThreadPool
    是一个静态类,这一事实进一步阻碍了其他线程池的使用。

    我投票结束这个问题,因为它应该属于site@SergeyBerezovskiy将问题更改为询问中是否已有可用的内容,NET framework alreadyTask是.NETCore中的新线程,它通过一个线程池进行管理。我投票将此问题作为主题外的问题结束,因为它应该属于site@SergeyBerezovskiy将问题更改为询问中是否已有可用的内容,NET framework alreadyTask是.NETCore中的新线程,它通过线程池进行管理。我不想覆盖默认的线程池,而是寻找一个单独的线程池,我可以使用它,并指定一次可以运行多少线程。我明白了,你读了我的第一段吗?
    WorkStealingTaskScheduler
    可能是最接近微软自己在托管代码中实现线程池的工具。但请参见同一项目中的
    LimitedConcurrencyLevel TaskScheduler
    。我不是要覆盖默认的线程池,而是一个单独的线程池,我可以对其进行设置,并指定一次可以运行多少线程池。我明白了,你读了我的第一段了吗?
    WorkStealingTaskScheduler
    可能是最接近微软自己在托管代码中实现线程池的工具。但请参见同一项目中的
    limitedconcurrensionleveltaskscheduler
    public class WorkerQueue : IWorkerQueue
    {
        private readonly Queue<WorkItem> _items = new Queue<WorkItem>();
    
        private int _max = 2; // Would be configurable
        private int _running;
        private Stopwatch _stopwatch;
    
        public WorkerQueue()
        {
            _stopwatch = new Stopwatch();
            _stopwatch.Start();
        }
    
        public void Add(WorkItem workItem)
        {
            lock (_items)
            {
                if (_running >= _max)
                {
                    Log($"Queuing Item {workItem.Name} - _running >= _max");
                    _items.Enqueue(workItem);
                    return;
                }
    
                _running++;
    
                Log($"Running Item {workItem.Name} - _running = {_running}");
                var task = Task.Run(workItem.Action);
    
                task.ContinueWith(t => OnActionCompleted(workItem.Name));
            }
        }
    
        private void Log(string msg)
        {
            Console.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId} @ {_stopwatch.ElapsedMilliseconds}ms : {msg}");
        }
    
        private void OnActionCompleted(string obj)
        {
            Log($"OnActionCompleted {obj}");
            WorkItem item = null;
    
            lock (_items)
            {
                if (_items.Count > 0)
                    item = _items.Dequeue();
                else
                    _running--;
            }
    
            if (item != null)
            {
                // Potential Stack Overflow if big queue builds up?
                // Probably should be a while loop rather than recursion?
                Log($"Running Next Item {item.Name}");
                item.Action();
                OnActionCompleted(item.Name);
            }
            else
            {
                Log($"Sleeping. _running = {_running}");
            }
        }
    }
    
        [Fact]
        public void Test()
        {
            var sb = new StringBuilder();
            Console.SetOut(new StringWriter(sb));
    
            var resetEvent = new ManualResetEventSlim();
    
            AddItem("A", 100);
            AddItem("B", 250);
            AddItem("C", 100);
            AddItem("D", 100);
            AddItem("E", 100);
            AddItem("G", 100, () =>
            {
                Thread.Sleep(250);
                resetEvent.Set();
            });
    
            resetEvent.Wait(2500);
    
            Assert.True(resetEvent.IsSet);
    
            _output.WriteLine("");
            _output.WriteLine("------------------ Test Finished ------------------");
            _output.WriteLine("------------------  Console Out  ------------------");
            _output.WriteLine("");
            _output.WriteLine(sb.ToString());
        }
    
    Thread 14 @ 8ms : Running Item A - _running = 1
    Thread 14 @ 8ms : Running Item B - _running = 2
    Thread 14 @ 8ms : Queuing Item C - _running >= _max
    Thread 14 @ 8ms : Queuing Item D - _running >= _max
    Thread 14 @ 8ms : Queuing Item E - _running >= _max
    Thread 14 @ 8ms : Queuing Item G - _running >= _max
    Thread 21 @ 110ms : OnActionCompleted A
    Thread 21 @ 110ms : Running Next Item C
    Thread 21 @ 211ms : OnActionCompleted C
    Thread 21 @ 211ms : Running Next Item D
    Thread 20 @ 260ms : OnActionCompleted B
    Thread 20 @ 260ms : Running Next Item E
    Thread 21 @ 311ms : OnActionCompleted D
    Thread 21 @ 311ms : Running Next Item G
    Thread 20 @ 360ms : OnActionCompleted E
    Thread 20 @ 360ms : Sleeping. _running = 1
    Thread 21 @ 662ms : OnActionCompleted G
    Thread 21 @ 662ms : Sleeping. _running = 0