控制每次线程池的并发线程的最大个数

【本人原创,欢迎交流和分形技术,转载请附上如下内容:

作者:itshare 【转自】http://www.cnblogs.com/itshare/

1. 实验目的:

      使用线程池的时候,有时候需要考虑服务器的最大线程数目和程序最快执行所有业务逻辑的取舍。
并非逻辑线程越多也好,而且新的逻辑线程必须会在线程池的等待队列中等待 ,直到线程池中工作的线程执行完毕,
才会有系统线程取出等待队列中的逻辑线程,进行CPU运算。

2.  解决问题:
     <a>如果不考虑服务器实际可支持的最大并行线程个数,程序不停往线程池申请新的逻辑线程,这个时候我们可以发现CPU的使用率会不断飙升,并且内存、网络带宽占用也会随着逻辑线程在CPU队列中堆积,而不断增大。
      <b>如果我们想在主程序有200个http网络通讯需要执行,如何每次循环用10个线程并发处理10个网络http通讯回话,下一次循环只有在上一次循环的10个线程都执行完毕后才会执行下一次循环,并且主程序监听和等待200个http网络通讯都在CPU线程池中执行完毕后,才会退出主程序。

3.  实现逻辑:
      我们通过两个AutoResetEvent和线程监听器Monitor,分别实现:
       <a>wait_sync:   任务线程的 并发执行,每次循环只处理最大10个线程分别对网络做http通讯回话。并且当前循环的10个线程都执行完毕后,才会进行下一次循环处理。
       <b> wait_main: 主程序线程的监听和等待,只有所有任务线程都执行完毕后,主程序线程才会退出程序。
       <c> list_Thread: 负责记录每次循环,CPU实际分配的系统线程的个数。和Monitor配合使用,Monitor.Enter(list_Thread)=占用共享线程资源的占用锁,Monitor.Exit(list_Thread)释放共享线程资源的占用锁。   
       <d> n_total_thread: 配合wait_main使用,记录全部逻辑线程,已经执行完毕的当前总个数,用来判断主线程是否还需要继续等待,还是可以结束主程序运行。

4. 主要代码:
    <a> 线程池控制代码,如下:

        /// <summary>
        /// 多线程调用WCF
        /// </summary>
        /// <param name="select">调用WCF的方式,1=Restful,2=Tcp</param>
        /// <param name="num"></param>
        static void DoTest_MultiThread(string select, long num)
        {
            int n_max_thread = 10; // 设置并行最大为10个线程
            int n_total_thread = 0; // 用来控制:主程序的结束执行,当所有任务线程执行完毕

            ILog log_add = new LogHelper("Add_Thread");
            ILog log_del = new LogHelper("Del_Thread");
            ILog log_wait = new LogHelper("Wait_Thread");
            ILog log_set = new LogHelper("Set_Thread");
            ILog log_for = new LogHelper("For_Thread");

            Console.Title = string.Format("调用WCF的方式 => {0}, 调用次数=> {1}"
                , select == "1" ? "Restful" : "Socket"
                , num);

            List<int> list_Thread = new List<int>();

            System.Threading.AutoResetEvent wait_sync = new System.Threading.AutoResetEvent(false); // 用来控制:并发最大个数线程=n_max_thread
            System.Threading.AutoResetEvent wait_main = new System.Threading.AutoResetEvent(false); // 用来控制:主程序的结束执行,当所有任务线程执行完毕

            DateTime date_step = DateTime.Now;
            for (long i = 0; i < num; i++)
            {
                Num_Query_Static++;
                if (i >0 && (i+1-1) % n_max_thread == 0) // -1 表示第max个线程尚未开始
                {
                    //log_wait.Info(string.Format("thread n= {0},for i= {1}", dic_Thread.Count, i + 1));
                    wait_sync.WaitOne(); // 每次并发10个线程,等待处理完毕后,在发送下一次并发线程
                }
                log_for.Info(string.Format("thread n= {0},for i= {1}", list_Thread.Count, i + 1));

                System.Threading.ThreadPool.QueueUserWorkItem
                    ((data) =>
                    {
                        int id = System.Threading.Thread.CurrentThread.ManagedThreadId;
                        System.Threading.Monitor.Enter(list_Thread);
                        list_Thread.Add(id);
                        System.Threading.Monitor.Exit(list_Thread);

                        log_add.Info(string.Format("id={0}, count={1}", id, list_Thread.Count)); // 日志

                        if (select == "1") // Restful方式调用
                        {
                            Query_Htty();
                        }
                        else
                        {
                            Query_Socket();
                        }

                        n_total_thread += 1;
                        if (list_Thread.Count == (n_max_thread) || n_total_thread == num)
                        {
                            list_Thread.Clear();
                            //log_set.Info(string.Format("thread n= {0},for i= {1}", dic_Thread.Count, i + 1));
                            //wait_sync.Set();
                            if (n_total_thread != num)
                            {
                                wait_sync.Set(); // 任务线程,继续执行
                            }
                            else
                            {
                                wait_main.Set(); // 主程序线程,继续执行
                            }
                        }
                    }, list_Thread);
            }

            wait_main.WaitOne();

            Console.WriteLine(string.Format("总测试{0}次,总耗时{1}, 平均耗时{2}"
                , num
                , (DateTime.Now - date_step).ToString()
                , (DateTime.Now - date_step).TotalMilliseconds / num));

            Query_Thread();
        }

 

 <b> WCF后台服务代码

        private static ILog log = new LogHelper("SeqService"); // 日志
        private static Dictionary<int, DateTime> dic_thread = new Dictionary<int, DateTime>(); // 线程列表

        private static long Num = 0; // 线程个数
        private static object lock_Num = 0;  // 共享数据-锁

        /// <summary>
        /// 在线申请流水号
        /// </summary>
        /// <returns></returns>
        [WebGet(UriTemplate = "GetSeqNum/Json", ResponseFormat = WebMessageFormat.Json)]
        public string GetSeqNumber()
        {
            lock (lock_Num)
            {
                Num++;
                int id_thread = System.Threading.Thread.CurrentThread.ManagedThreadId;
                DateTime now = DateTime.Now;
                if (!dic_thread.TryGetValue(id_thread, out now))
                {
                    dic_thread.Add(id_thread, DateTime.Now);
                }

            }
            string ret = DateTime.Now.ToString("yyyyMMdd") + Num.ToString(new string(‘0‘, 9));  

            log.Info(string.Format("{0}, Thread={1}/{2}", ret, System.Threading.Thread.CurrentThread.ManagedThreadId, dic_thread.Count));
            return ret;
        }

  

5.  实验结果

1. 10000个WCF网络http请求,CPU分成每次10个(10可以按需求调整)线程并发执行,并且主程序在所有请求都执行完毕后,才退出主程序。

1. 前端日志:LogFile\Add_Thread\Info

Thread Id / Thread Num

2. WCF日志:LogFile\SeqService\Info

Thread Id / Thread Num

时间: 2024-10-15 01:05:02

控制每次线程池的并发线程的最大个数的相关文章

如何处理线程池的并发?

[前言]我们从事Android开发以来,都自始自终被灌输着处理耗时的任务时要在非UI线程做.于是我们有了各种处理并发的编程手段,无论是自己用new Thread(Runnable)新起工作线程(Worker thread),还是利用Android提供的API(AsnyTask,CursorLaoder等)都是处理耗时任务的解决方案.但是在一个大型的应用程序中,如果我们需要处理数量很多且频繁的耗时任务时,如果还是采用之前的手段,无疑会带来很多不便:一来频繁创建销毁线程会造成资源(内存和Cpu)的浪

高并发、任务执行时间短的业务怎样使用线程池?并发不高、任务执行时间长的业务怎样使用线程池?并发高、业务执行时间长的业务怎样使用线程池?

(1)高并发.任务执行时间短的业务,线程池线程数可以设置为CPU核数+1,减少线程上下文的切换(2)并发不高.任务执行时间长的业务要区分开看:a)假如是业务时间长集中在IO操作上,也就是IO密集型的任务,因为IO操作并不占用CPU,所以不要让所有的CPU闲下来,可以加大线程池中的线程数目,让CPU处理更多的业务b)假如是业务时间长集中在计算操作上,也就是计算密集型任务,这个就没办法了,和(1)一样吧,线程池中的线程数设置得少一些,减少线程上下文的切换(3)并发高.业务执行时间长,解决这种类型任务

深入浅出 Java Concurrency (33): 线程池 part 6 线程池的实现及原理 (1)[转]

线程池数据结构与线程构造方法 由于已经看到了ThreadPoolExecutor的源码,因此很容易就看到了ThreadPoolExecutor线程池的数据结构.图1描述了这种数据结构. 图1 ThreadPoolExecutor 数据结构 其实,即使没有上述图形描述ThreadPoolExecutor的数据结构,我们根据线程池的要求也很能够猜测出其数据结构出来. 线程池需要支持多个线程并发执行,因此有一个线程集合Collection<Thread>来执行线程任务: 涉及任务的异步执行,因此需要

线程池和异步线程

目录: 1 什么是CLR线程池? 2 简单介绍下线程池各个优点的实现细节 3 线程池ThreadPool的常用方法介绍 4 简单理解下异步线程 5 异步线程的工作过程和几个重要的元素 6 有必要简单介绍下Classic Async Pattern 和Event-based Async Pattern 7 异步线程的发展趋势以及.net4.5异步的简化 8 本章示例 自定义一个简单的线程池 Asp.net异步IHttpAsyncHandler示例 9 本章总结 1 什么是CLR线程池? 在上一章中

Java多线程系列--“JUC线程池”02之 线程池原理(一)

ThreadPoolExecutor简介 ThreadPoolExecutor是线程池类.对于线程池,可以通俗的将它理解为"存放一定数量线程的一个线程集合.线程池允许同时运行的线程数量就是线程池的容量:当添加到线程池中的线程超过它的容量时,会有一部分线程阻塞等待.线程池会通过相应的调度策略和拒绝策略,对添加到线程池中的线程进行管理." ThreadPoolExecutor数据结构 ThreadPoolExecutor的数据结构如下图所示: 各个数据在ThreadPoolExecutor

Java多线程系列--“JUC线程池”01之 线程池架构

概要 前面分别介绍了"Java多线程基础"."JUC原子类"和"JUC锁".本章介绍JUC的最后一部分的内容——线程池.内容包括:线程池架构图线程池示例 转载请注明出处:http://www.cnblogs.com/skywang12345/p/3509903.html 线程池架构图 线程池的架构图如下: 1. Executor 它是"执行者"接口,它是来执行任务的.准确的说,Executor提供了execute()接口来执行

Android 线程池来管理线程

网上讲了很多的关于线程池的例子.其实在我们实际应用中,譬如说,一个应用的线程是怎样来管理的,我们就可以说,我们可以使用线程池来管理线程. eg: class DianLiang1 implements Runnable { @Override punlic void Run{ system.println("*************111111111111111111111****************"); } } class DianLiang2 implements Runn

终止线程池对应某个线程

加入某个线程池中有多个线程: ThreadPool.addThread(t1); ThreadPool.addThread(t2); ... ThreadPool.addThread(tn); 现在想终止第m个线程做法思想如下: ①创建一个hashMap,将所创建的线程以及对应每个线程唯一标识放进去:consoleThreadMap.put(serial, Thread.currentThread()); ②在线程正常执行结束后从hashMap中移除:consoleThreadMap.remov

通过设置线程池的最小线程数来提高task的效率,SetMinThreads。

http://www.cnblogs.com/Charltsing/p/taskpoolthread.html task默认对线程的调度是逐步增加的,连续多次运行并发线程,会提高占用的线程数,而等若干秒不运行,线程数又会降低.这样,会影响程序多次运行的效率. 即使使用了TaskCreationOptions.LongRunning参数,依然效率偏低.对于一些固定执行时间的线程,我们可以提高线程池的最小线程数,来显著提高task多线程的效率. ThreadPool.SetMinThreads(10