C# 多线程与队列

使用多线程的时候,如果线程执行的函数需要记录返回结果,那么要保证存储结果的对象安全可靠。

ConcurrentQueue  高效的线程安全队列,能够在使用多线程的时候保障程序安全可靠

一:参数很多,需要多次调用同一函数并汇总返回结果

  //参数很多,单方法,需要反复多次调用
        public static void TaskMoreParam()
        {
            var paramlist = new List<int>();//大量的参数
            for (var i = 0; i < 100; i++)
            {
                paramlist.Add(i);
            }

            // 将参数放到队列,然后开启线程,线程里面队列来调用方法。
            List<Task> tasks = new List<Task>();
            //入参
            var Queue = new ConcurrentQueue<int>();
            //结果集
            var rQueue = new ConcurrentQueue<int>();

            //将参数放到队列中
            for (int i = 0; i < paramlist.Count; i++)
            {
                Queue.Enqueue(i);
            }

            #region 使用task
            for (int i = 0; i < 10; i++)
            {
                //创建多线程
                var task = Task.Run(() =>
                {
                    //如果参数队列里面还有数据则继续执行
                    while (Queue.Count > 0)
                    {
                        //从参数队列里面取出参数,同时将参数从队列中移除
                        Queue.TryDequeue(out int a);
                        //调用具体函数,将返回结果存放在队列中
                        rQueue.Enqueue(GetNumber(a));
                    }
                });
                tasks.Add(task);
            }
            //等线程全部执行完毕。
            Task.WhenAll(tasks.ToArray());
            #endregion

            #region 使用 Parallel
            //Queue 将队列作为参数,比集合的好处在于取数据避免并发
            //假如 函数执行很慢,多线程在跑的时候可能会并发,两个线程拿到同一个参数导致有参数丢失
            ParallelLoopResult res = Parallel.ForEach(Queue, new ParallelOptions() { MaxDegreeOfParallelism = 10 }, (i) =>
            {
                rQueue.Enqueue(GetNumber(i));
            });
            #endregion

            var resultlist = rQueue.ToList();
        }

  执行函数

  //待执行函数
        public static int GetNumber(int i)
        {
            Thread.Sleep(1000);
            return i * 2;
        }

  二:同一参数,多函数调用,而且函数耗时,需要统计返回结果

   //多方法。很耗时
        public static void TaskSlow()
        {
            int param = 1;

            // 将参数放到队列,然后开启线程,线程里面队列来调用方法。
            List<Task> tasks = new List<Task>();
            //入参
            var Queue = new ConcurrentQueue<Func<int, int>>();
            //结果集
            var rQueue = new ConcurrentQueue<int>();

            //将方法放入队列
            Queue.Enqueue(GetNumber);
            Queue.Enqueue(GetNumber1);
            Queue.Enqueue(GetNumber2);

            #region 使用 Parallel
            //Queue 将队列作为参数,比集合的好处在于取数据避免并发
            //假如 函数执行很慢,多线程在跑的时候可能会并发,两个线程拿到同一个参数导致有参数丢失
            ParallelLoopResult res = Parallel.ForEach(Queue, new ParallelOptions() { MaxDegreeOfParallelism = 10 }, (fun) => rQueue.Enqueue(fun(param)));
            #endregion

            var resultlist = rQueue.ToList();
        }

  

  //待执行函数
        public static int GetNumber(int i)
        {
            Thread.Sleep(1000);
            return i * 2;
        }
        public static int GetNumber1(int i)
        {
            Thread.Sleep(1000);
            return i * 2;
        }
        public static int GetNumber2(int i)
        {
            Thread.Sleep(1000);
            return i * 2;
        }

  三:记录一次踩坑

将多线程的结果存放在List结果中,这里会有问题,List是一种线性表,内部可以是以一种数组来存储的,那么在多线程情况下,可能多条结果同时赋值给了一个数组,最后结果覆盖,于是返回结果丢失

  //参数很多,需要反复多次调用
        public static void TaskMoreParam1()
        {
            var paramlist = new List<int>();//大量的参数
            for (var i = 0; i < 100; i++)
            {
                paramlist.Add(i);
            }

            // 将参数放到队列,然后开启线程,线程里面队列来调用方法。

            List<Task> tasks = new List<Task>();
            //入参
            var Queue = new ConcurrentQueue<int>();
            //结果集
            var rQueue = new List<int>();

            //将参数放到队列中
            for (int i = 0; i < paramlist.Count; i++)
            {
                Queue.Enqueue(i);
            }

            #region 使用 Parallel
            //Queue 将队列作为参数,比集合的好处在于取数据避免并发
            //假如 函数执行很慢,多线程在跑的时候可能会并发,两个线程拿到同一个参数导致有参数丢失
            ParallelLoopResult res = Parallel.ForEach(Queue, new ParallelOptions() { MaxDegreeOfParallelism = 10 }, (i) =>
            {
                Console.WriteLine(i);
                rQueue.Add(GetNumber(i));//此处有问题
            });
            #endregion

            var resultlist = rQueue.ToList();
            var str = string.Join(",", resultlist);
        }

  

 

posted @ 2022-07-20 17:33  wanwanwhl  阅读(4373)  评论(0)    收藏  举报