线程池与并行度

展示线程池如何工作于大量的异步操作,以及它与创建大量单独的线程的方式有什么不同。

大量创建线程(消耗内存、CPU系统资源,请观察)

使用线程池:执行的时间更长,但对系统资源消耗要小的多

using System;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;

namespace Test
{
    class Program
    {
        private static void UseThreads(int count)
        {
            //通过CountdownEvent可以在主线程中线程池中的任务运行,主线程要等待线程池中的任务完成之后才能继续
            using (var countdown = new CountdownEvent(count))//这里给CountdownEvent指定计数为500
            {
                for (int i = 0; i < count; i++)
                {
                    //使用普通线程
                    var t1 = new Thread(() =>
                    {
                        //CurrentThreadInfo("UseThreads()的");

                        Thread.Sleep(TimeSpan.FromMilliseconds(100));
                        countdown.Signal();//每次循环CountdownEvent在这里计数减1,一直减少到0
                    });
                    t1.Start();
                }

                countdown.Wait();//主线程一开始在这里停止并等待,CountdownEvent计数减少到0的时候,这里主线程开始执行
            }
        }

        private static void UseThreadPool(int count)
        {
            using (var countdown = new CountdownEvent(count))
            {
                for (int i = 0; i < count; i++)
                {
                    //使用线程池
                    ThreadPool.QueueUserWorkItem(_ =>
                    {
                        //CurrentThreadInfo("UseThreadPool()的");

                        Thread.Sleep(TimeSpan.FromMilliseconds(100));
                        countdown.Signal();
                    });
                }

                countdown.Wait();
            }
        }

        /// <summary>
        /// 向线程池放入异步操作
        /// </summary>
        static void Main()
        {
            //CurrentThreadInfo("主线程Main()的");

            int count = 500;


            CodeTimer.Initialize();

            int iteration = 2;
            CodeTimer.Time("UseThreads", iteration, () =>
            {
                Stopwatch sw = new Stopwatch();
                sw.Start();
                UseThreads(count);
                sw.Stop();
                Console.WriteLine("使用简单线程耗时:{0} - 计数:{1}", sw.ElapsedMilliseconds, sw.ElapsedTicks);
            });

            CodeTimer.Time("UseThreadPool", iteration, () =>
            {

                Stopwatch sw2 = new Stopwatch();
                sw2.Start();
                UseThreadPool(count);
                sw2.Stop();
                Console.WriteLine("使用线程池中耗时:{0} - 计数:{1}", sw2.ElapsedMilliseconds, sw2.ElapsedTicks);
            });


            Console.WriteLine("执行完成");
            Console.ReadLine();
        }



        /// <summary>
        /// 当前线程信息
        /// </summary>
        private static void CurrentThreadInfo(string name)
        {
            StringBuilder builder = new StringBuilder();
            builder.AppendLine("");
            builder.AppendLine(String.Format("{0}线程Id:\t\t{1}", name, Thread.CurrentThread.ManagedThreadId));
            builder.AppendLine(String.Format("{0}是否使用线程池:\t{1}", name, Thread.CurrentThread.IsThreadPoolThread));
            builder.AppendLine(String.Format("{0}是否后台线程:\t{1}", name, Thread.CurrentThread.IsBackground));
            builder.AppendLine(String.Format("{0}线程状态:\t\t{1}", name, Thread.CurrentThread.ThreadState.ToString()));
            builder.AppendLine(String.Format("{0}当前时间:\t\t{1}", name, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")));
            builder.AppendLine("");

            Console.WriteLine(builder.ToString());
        }
    }
}

工作原理:

使用普通线程

当主程序启动时,创建了很多不同的线程,每个线程都运行一个操作。该操作打印出线程ID并阻塞线程100毫秒。结果我们创建了500个线程,全部并行运行这些操作。虽然在我的机器上的总耗时是300毫秒,但是所有线程消耗了大量的操作系统资源

 

使用线程池

然后我们使用了执行同样的任务,只不过部位每个操作创建一个线程,儿将他们放入到线程池中。然后线程池开始执行这些操作。线程池在快结束时创建更多的线程,但是仍然花费了更多的时间,在我机器上是12秒。我们为操作系统节省了内存和线程数,但是为此付出了更长的执行时间。

posted @ 2020-03-08 17:57  无聊的蚂蚁  阅读(392)  评论(0编辑  收藏  举报