• 线程池和任务工厂实现多线程异步运行


    将多个线程在线程池中运行

    知识点保温

    引用一下微软官网的介绍:

    线程池: https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.threadpool?redirectedfrom=MSDN&view=netframework-4.7.2


    直接上Demo

    多线程运行 VS 单线程运行

        /// <summary>
        /// 高效多线程测试
        /// </summary>
        public class ThreadTestController : ApiController
        {
            static AutoResetEvent autoResetEvent = new AutoResetEvent(false);
            private static string keySet = System.Configuration.ConfigurationManager.AppSettings["KeySetting"];
    
            /// <summary>
            /// 多线程运行 -- 线程池
            /// </summary>
            /// <returns></returns>
            public ApiReponseBaseModel MultThreads()
            {
                ApiReponseBaseModel result = new ApiReponseBaseModel();
                List<string> list = new List<string>() { "", "", "", "", "", "", "", "" };
                ApiReponseBaseModel masterVal = new ApiReponseBaseModel() { Id = 1, Success = false, Message = "one" };
                List<string> newList = new List<string>();
                try
                {
                    int i = 0;
                    foreach (var item in list)
                    {
                        try
                        {
                            if (item == "") throw new Exception("人造异常");
                            ThreadPool.QueueUserWorkItem(new WaitCallback(delegate (object obj)
                            {
                                if (string.IsNullOrEmpty(item)) { i++; newList.Add((i).ToString() + ":" + "为空了"); return; }  //保证每个子线程都有执行 i++
                                try
                                {
                                    #region 
                                    ApiReponseBaseModel val = new ApiReponseBaseModel
                                    {
                                        Id = masterVal.Id,
                                        Success = masterVal.Success,
                                        Message = masterVal.Message
                                    };
                                    #endregion
                                    val.Message = item;
    
                                    Thread.Sleep(500);
                                    lock (newList)
                                    {
                                        newList.Add(i.ToString() + ":" + val.Message);
                                    }
                                }
                                catch (Exception ex)
                                {
                                    newList.Add((i+1).ToString() + ":" + ex.Message);
                                }
                                finally
                                {
                                    if (++i == list.Count) autoResetEvent.Set();
                                }
                                
                            }), null);
                        }
                        catch (Exception ex)
                        {
                            i++;    //发生异常,一定要记得 i++
                            newList.Add(i.ToString() + ":" + ex.Message);
                            continue;
                        }
                        //finally  //【误区】千千万万不要在这里写逻辑判断(i == list.Count 或者写 i++),这个finally是主线程的,不一定会在子线程之后执行的
                        //{
                        //    i++;
                        //    if (i == list.Count) autoResetEvent.Set();
                        //}
                    }
    
                    autoResetEvent.WaitOne();
    
                    newList.Add("the end");
                    result.Data = newList;
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                
                return result;
            }
    
            /// <summary>
            /// 单线程运行
            /// </summary>
            /// <returns></returns>
            public ApiReponseBaseModel SingleThread()
            {
                ApiReponseBaseModel result = new ApiReponseBaseModel();
                List<string> list = new List<string>() { "", "", "", "", "", "", "", "" };
                ApiReponseBaseModel masterVal = new ApiReponseBaseModel() { Id = 1, Success = false, Message = "one" };
                List<string> newList = new List<string>();
                int i = 0;
                foreach (var item in list)
                {
                    if (string.IsNullOrEmpty(item)) { i++; newList.Add((i).ToString() + ":" + "为空了"); continue; }
                    #region 
                    ApiReponseBaseModel val = new ApiReponseBaseModel
                    {
                        Id = masterVal.Id,
                        Success = masterVal.Success,
                        Message = masterVal.Message
                    };
                    #endregion
                    val.Message = item;
                    Thread.Sleep(500);
                    newList.Add(i.ToString() + ":" + val.Message);
                    i++;
                }
                newList.Add("the end");
                result.Data = newList;
                return result;
            }
    
        }

    结果:

    解析:

    1、以上两个方法的运行,我们都在方法中休眠了,用以突显出多线程异步执行达到运行更快的效果。

    2、在第一个方法(多线程运行 -线程池)中,用到了线程池,其关键在于 AutoResetEvent 的使用,它的.Set() 和 WaitOne() 是关键点。

          WaitOne() 会阻塞当前的线程,而等当前 WaitHandle 发来的信息,Set() 方法就是发出信号的。

    3、那么很重要的地方来了,就是怎么在逻辑中表达,所需要计算的数据和执行的进程都已经执行完了,而在恰当的地方适当的时候发起信号,激活主线程。

    4、以上多线程方法中,我们还用到了个 lock 锁,这也是极其微妙关键的。我们的多个子线程运行的程序模块中,都有访问了一个共同的对象 newList。newList 是主线程的一个 引用类型变量,为了防止多个线程在同一个时间点对这个变量进行更改操作(Add),

         而引发的异常错误,我们在做这类操作的时候,给这个共同的资源(newList)加上锁,让这样的操作一个接着一个来。

         进程中的 val 这个变量,变量类型是(ApiReponseBaseModel),也是个引用类型。我们不在子进程中直接用主线程的 masterVal 变量,也是这个原因,防止多个子线程同时对共同资源做修改操作。

    5、WaitHandler 类的小图解


    我们再试个任务工厂的Demo

    知识点保温

    任务工厂的知识保温链接:https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskfactory?view=netframework-4.7.2

    需要温习任务工厂的小伙伴们可以进入以上链接,吸食日夜精华


    直接上菜

            /// <summary>
            /// 多线程运行 -- 任务工厂
            /// </summary>
            /// <returns></returns>
            public ApiReponseBaseModel TaskFactory()
            {
                ApiReponseBaseModel result = new ApiReponseBaseModel();
                List<string> list = new List<string>() { "", "", "", "", "", "", "", "" };
                ApiReponseBaseModel masterVal = new ApiReponseBaseModel() { Id = 1, Success = false, Message = "one" };
                List<string> newList = new List<string>();
    
                List<Task> taskList = new List<Task>();
                int i = 0;
                list.ForEach(p =>
                {
                    taskList.Add(Task.Factory.StartNew(() =>
                    {
                        if (string.IsNullOrEmpty(p)) { i++; newList.Add((i).ToString() + ":" + "为空了"); return; }  //保证每个子线程都有执行 i++
                        try
                        {
                            if (p == "") throw new Exception("人造异常");
                            #region 
                            ApiReponseBaseModel val = new ApiReponseBaseModel
                            {
                                Id = masterVal.Id,
                                Success = masterVal.Success,
                                Message = masterVal.Message
                            };
                            #endregion
                            val.Message = p;
    
                            Thread.Sleep(500);
                            lock (newList)
                            {
                                newList.Add(i.ToString() + ":" + val.Message);
                            }
                        }
                        catch (Exception ex)
                        {
                            newList.Add((i + 1).ToString() + ":" + ex.Message);
                        }
                    }));
    
                    //taskList.Add(Task.Factory.StartNew(fn =>
                    //{
    
                    //}, null));
                });
                
                Task finalTask = Task.Factory.ContinueWhenAll(taskList.ToArray(), fn => {
                    newList.Add("finallyTask the end");
                });
                finalTask.Wait();
                newList.Add("main thread the end");
                result.Data = newList;
                return result;
            }

    效果:

    解析:

    1、我们在任务工厂里边搞了几个任务,每个任务我们都休眠,模仿长时间运行效果。

    2、任务工厂的关键在于 ContinueWhenAll() 方法。顾名思义,当该方法参数所指的任务都执行的时候,执行这一方法,这个方法返回一个任务,我们定义一个任务变量(finalTask)来接收。

         紧接着,我们放这个变量(finalTask)进行等待,finalTask.Wait()。


    小总结

     通过以上三个方法的比较

    1、多线程比单线程是有优势的,通常情况下运行时间是会更快的,除非服务器爆了

    2、在易于编写使用的角度来说,个人觉得任务工厂的办法会比线程池的方法好一些。

    3、多读书,多敲码。            ----- 致爱码仕 & 牧码人


    author:韦小明

    本文路径:http://www.cnblogs.com/youler/p/9845473.html


  • 相关阅读:
    关于iTunes11.1 不能刷自制固件的解决方案
    关于网上流传的四个原版Windows XP_SP2全面了解
    什么是S-OFF,什么是S-ON,HBOOT命令,玩转Android
    用UltraISO制作的u盘ubuntu11.04,启动失败解决方案
    关于个人防火墙的真相
    AVAST 4.8
    忆旧:关于“天网防火墙”的破解
    McAfee VirusScan Enterprise
    记录日志框架:log4net使用
    C#网络编程二:Socket编程
  • 原文地址:https://www.cnblogs.com/youler/p/9845473.html
Copyright © 2020-2023  润新知