【问题标题】:Thread Pools - restricting calls to certain methods线程池 - 限制对某些方法的调用
【发布时间】:2012-05-01 09:49:34
【问题描述】:

有没有办法告诉线程池管理器只有 x 个调用特定方法或方法组的线程?

我有一个应用程序,我在所有地方都使用线程池工作线程,它可以流畅地工作;但是,我委托给工作线程的任务之一是 Web 服务调用,它将拒绝超过 5 个并发请求。我不想将线程池限制为 5 个线程,因为许多其他东西使用线程并且可以处理更多。

有没有办法“划分”线程池来表示“在任何时间点都有最多 x 个线程在做这个特定的事情,但是其余的线程可以去做其他事情吗?

【问题讨论】:

    标签: c# multithreading c#-4.0


    【解决方案1】:

    您可以使用多个线程池。拥有最多 5 个线程的线程池 A 用于对 Web 服务的请求,而线程池 B 的最大值则更高。

    【讨论】:

    • 如何创建一个新的、独立的线程池?它似乎没有构造函数。
    • 嗯……对我来说,Java 世界的时间似乎太多了。我想您需要创建自己的线程池才能做到这一点,而这在这里可能不值得。
    • 这也是我的第一个想法 :(( 第二个想法,如果你不能创建另一个线程池实例 - 为什么?它是一个类,所以我为什么不能创建一个?这只是愚蠢的说法限制。
    • 我猜这个决定是为了防止子系统和库打开他们自己的池,并以倍数超额订阅 CPU。这个决定有问题,但合理。
    • 这是不合理的,恕我直言。它从语言中吸取了灵活性。独立子系统只是....正常! F.. M$...
    【解决方案2】:

    创建另一个线程池和 SetMaxThreads(5) - 这是最简单的方法。

    好的,你不能用 Threadpool 类来做。

    这样我就不会被否决:

    public abstract class Task {
        public EventHandler FonComplete;
        public ThreadPool myPool;
        protected int param;
        public Exception error;
        public Task(int inParam, EventHandler OnDone) { param = inParam; FonComplete = OnDone; }
        public abstract void run();
    };
    
    
    public class PoolThread{
    private
        BlockingCollection<Task> FinQueue;
    public
        PoolThread(BlockingCollection<Task> inQueue)
        {
           FinQueue=inQueue; 
        }
        Task inMess;
        public void run(){
            while(true){
                inMess=FinQueue.Take();
                if(inMess==null) return;
                try
                {
                    inMess.run();
                    inMess.error = null;
                }
                catch (Exception e)
                {
                    inMess.error = e;
                }
                inMess.FonComplete(inMess, null);
            }
        }
    };
    
    public class ThreadPool {
        int FthreadCount;
        BlockingCollection<Task> queue;
        void startThread(){
                PoolThread thisPoolThread=new PoolThread(queue);
                Thread thisThread=new Thread(new ThreadStart(thisPoolThread.run));
                thisThread.Priority = ThreadPriority.BelowNormal;
                thisThread.IsBackground = true;
                thisThread.Start();
        }
        void SetThreadCount(int newCount){
            while(FthreadCount<newCount){startThread();};
            while(FthreadCount>newCount){
                queue.Add(default(Task));
                FthreadCount--;
            };
        }
        public ThreadPool(int initThreads){
            queue=new BlockingCollection<Task>();
            for(FthreadCount=0;FthreadCount<initThreads;FthreadCount++) startThread();
        }
        public int threadCount{
            get{return FthreadCount;}
            set
            {
                while (FthreadCount < value) {
                    startThread();
                    FthreadCount++;
                };
                while (FthreadCount > value)
                {
                    queue.Add(default(Task));
                    FthreadCount--;
                }
            }
        }
    
        public void submit(Task task){
            task.myPool=this;
            queue.Add(task);
        }
    };
    
    }
    

    它不像‘真正的’System.Threading.Threadpool,而是一个线程数固定的线程池

    【讨论】:

    • 我可能遗漏了一些东西,但似乎没有办法做到这一点。
    • 什么?我;确定我在某处读过它?为什么Servy和我自己都立刻想到了同一个答案?
    • @MartinJames 直到您展示如何创建另一个线程池,这只是一个评论,而不是答案。
    • 好吧,至少我在尝试... :((
    • 这似乎是正确的方法;有点令人沮丧,这是必要的,但是哦。
    【解决方案3】:

    使用信号量将稀缺资源的访问权限限制为最大。 5.

    可以将信号量配置为仅允许 N 个线程的并发访问。您需要将 Semaphore 配置为 N=5,并让所有线程在调用 web 服务之前等待它。

    【讨论】:

    • 你能解释一下吗?我不关注。
    • 不幸的是,这在这种情况下不起作用。额外的池线程将在信号量上被阻塞,而不是可用于处理其他任务。
    • 是的,它们将被阻塞,但线程池只会产生新线程来替换它们。线程池可以检测阻塞。
    • 哇,我以前从未听说过这个。我会试着用我的大脑来解决它。
    • 我不太确定阻止 [no.提交的网络任务 -5] 线程是一个好主意,但我没有理由认为它不起作用。这么简单当然值得一试!
    【解决方案4】:

    首先,使用Task 类而不是直接使用ThreadPool。启动一个父任务,该任务循环遍历您的每个工作项并启动一个子任务。父任务将使用信号量来限制并发子任务的数量。

    这比让您的子任务在信号量上等待要好得多,因为现在我们只有一个池线程在等待信号量而不是很多。

    var parent = Task.Factory.StartNew(
      () =>
      {
        var semaphore = new SemaphoreSlim(5, 5);
        foreach (var workitem in YourWorkItems)
        {
          var capture = workitem;
          semaphore.Wait();
          Task.Factory.StartNew(
            () =>
            {
              try
              {
                CallWebService(capture);
              }
              finally
              {
                semaphore.Release();
              }
            }, TaskCreationOptions.AttachedToParent);
        }
      }, TaskCreationOptions.LongRunning);
    
    // Optionally wait for the parent to complete here.
    // Because our child tasks are attached this will wait until everything is done.
    parent.Wait(); 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多