线程池 + 轮询 C# .Net 3.5

4

你好,我是一名新手,对多线程不太了解,希望能请教您的建议和指导。

我们在服务器上运行一个服务,用于为客户端轮询数据以进行通知。我们希望该服务能够更快地处理数据。目前,我们现有的服务在单个线程上轮询并处理数据,这有时会导致每小时通知的延迟。我的计划是使用ThreadPool来实现并发处理数据。我有以下代码可以模拟我的计划和想法。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Mail;
using System.Security;
using System.Text;
using System.Threading;
using System.Xml;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Net.Sockets;
using System.Security.Authentication;
using System.Web; 

namespace ThreadPooling
{
    class Program
    {
        static int nMaxRecord = 0;
        static ManualResetEvent mre = new ManualResetEvent(false);
        static Timer TestThread = null;
        static void Main(string[] args)
        {
            TestThread = new Timer(new TimerCallback(ProcessWithThreadPoolMethod), null, 500, Timeout.Infinite);
            Thread.Sleep(Timeout.Infinite);
        }

        static void ProcessWithThreadPoolMethod(object ostate) // Sample processing of data
        {
            nMaxRecord = 1300;
            ThreadPool.SetMaxThreads(3, 0);
            for (int i = 0; i < 1300; i++)
            {
                ThreadPool.QueueUserWorkItem(ProcessWithThreadMethod, i);
            }

            mre.WaitOne();
            Console.WriteLine("Test");

            TestThread.Change(5000, Timeout.Infinite);
        }

        static void ProcessWithThreadMethod(object callback)
        {
            for (int i = 0; i <= 10; i++)
            {
                Console.WriteLine((int)callback);
            }

            if(Interlocked.Decrement(ref nMaxRecord) == 0)
            {
                mre.Set();
            }
        }
    }
}

在运行控制台应用程序时,我注意到线程计数不断增加,尽管我通过ThreadPool将最大线程数限制为3。这样做是否正确?想要一些指导并了解我的思路的优缺点。


1
@MrinalKamboj; 这个在 .net 3.5 中可用吗? - Stefan
1
@MrinalKamboj,“从.NET Framework 4开始,TPL是首选的方式。” 来源 OP使用的是3.5版本。 - Fildor
1
@Stefan 没有提到那一部分,是的,它是从 .Net 4.0 开始的。 - Mrinal Kamboj
1
@JonathanDaniel:是的,线程池只是调节生成的线程数。信号量就像保安一样:它调节并发活动线程。需要注意的是:它是通过等待来实现这一点的,因此,如果你启动了1300个线程,并允许同时有3个活跃线程,那么1297个线程将处于等待状态。 - Stefan
显示剩余4条评论
2个回答

2

你应该测试以下返回值:

ThreadPool.SetMaxThreads(3, 0); //returns false on normal machines.

由于以下原因,无法处理更改:
您不能将工作线程或I/O完成线程的最大数量设置为小于计算机上处理器数量的数字。要确定有多少个处理器存在,请检索Environment.ProcessorCount属性的值。另外,您不能将工作线程或I/O完成线程的最大数量设置为小于相应的最小工作线程或I/O完成线程数量的数字。要确定线程池的最小大小,请调用GetMinThreads方法。
请参见:MSDN 因此,您可以执行以下操作:
ThreadPool.SetMaxThreads(16, 16);

但我猜你是想降低线程池的速度。一般来说,这不是一个好主意。您需要为这种逻辑找到替代方案。

信号量可能是一个选择,或者像@Fildor描述的模式。


谢谢!!!,我的错,我没有能够阅读SetMaxThread文档。所以我们不能将最大线程数限制在处理器数量以下。我们想要避免CPU峰值,这就是为什么我设置了3的原因。当我在我们的staging服务器上测试服务时,我还注意到它创建了1K +的线程,尽管CPU使用率在40% - 50%左右,这正常吗? - Jonathan Daniel
2
然后使用生产者-消费者模式。不要为每个项目使用一个线程,而是将项目保留在队列中,并使用您认为合适的线程数量进行消耗。@JonathanDaniel - Fildor
我也注意到它创建了1k+的线程,尽管CPU使用率在40% -50%左右,这正常吗?这取决于它正在做什么。1k +个线程很多。CPU使用率也很高。但是,如果您的系统正在处理大量数据,则有道理。如果您没有预期这些负载:那么一定有问题。 - Stefan
@Fildor 谢谢,显然我们无法升级到4,因为我们的大多数服务和项目构建都使用3.5,并且与其他项目紧密耦合。 - Jonathan Daniel
1
刚刚发现这个:https://dev59.com/d3RB5IYBdhLWcg3wEDul#47179576。也许它可以给你“灵感”。 - Fildor
显示剩余2条评论

0

你不能对线程池进行限制,但为什么不使用一个简单的增量/减量计数器,在启动新线程之前进行检查呢?

伪代码如下:

volatile int currentThreadCount = 0;

void myWorkLauncher()
{
   while(<I have work to do>)
   {
      if(currentThreadCount < threshold)
      {
          currentThreadCount ++;
          ThreadPool.QueueUserWorkItem(workerFunc);
      }
      else
      {
          Thread.Sleep(500);
      }
   }
   Thread.Sleep(500);
}

workedFunc的最后一行只是将值递减。

你可以做各种花哨的事情,比如将workerFunc包装在Action()中,这本身就会递减计数器,使得workerFunc不需要与myWorkLauncher类有任何关联。或者你可以用AutoResetEvent或类似的东西来替换简单的Thread.Sleep。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接