• C# 多线程、异步线程、线程池相关知识


    /*
    线程池ThreadPool类会在需要时增减池中线程的线程数,直到最大的线程数。池中的最大线程数是可配置的。
    在双核CPU中,默认设置为1023个工作线程和1000个I/O线程。也可以指定在创建线程池时应立即启动的最小线程数,
    以及线程池,中可用的最大线程数。如果有更多的作业要处理,线程池中线程的个数也到了极限,
    最新的作业就要排队,且必须等待线程完成其任务。
    */
    
    //下面这个方法是一个符合WaitCallBack委托的方法:
    static void WaitCallBackMethod(object param)
    {
         for (int i = 0; i < 5; i++)
         {
             Console.WriteLine(String.Format("Thread {0} is running", param));
             Thread.Sleep(1000);
         }
    }
    //然后在主线程里给线程池添加方法,QueueUserWorkItem()方法的第二个参数是个object类型的参数,可传入一个数据到线程中
    
    static void Main(string[] args)
    {
         for (int i = 1; i <= 3; i++)
         {
             ThreadPool.QueueUserWorkItem(WaitCallBackMethod, i);
         }
         Console.Read();
    }
    
    /////////////////////////////////////////////////////////////////
    //Task任务
    1、Task类构造函数
    
    使用Task类的构造函数。实例化Task对象时,任务不会立即运行,而是指定Created状态。
    接着调用Task类的Start()方法来启动任务。
    使用Task类时,除了调用Start()方法,还可以调用RunSynchronously()方法。
    这样,任务也会启动,但是同时调用。默认情况下,任务是异步运行的。
    Task类的构造函数接收一个无参无返回值的委托:
    
    Task task = new Task(TaskMethod);
    task.Start();
    
    下面是TaskMethod方法:
    static void TaskMethod()
    {
        for (int i = 0; i < 10; i++)
        {
            Console.WriteLine(String.Format("Running in a task. Task ID: {0}", Task.CurrentId));
            Thread.Sleep(500);
        }
    }
    
    方法里用Task.CurrentId属性取得当前任务ID。下面是主线程:
    static void Main(string[] args)
    {
        Task task = new Task(TaskMethod);
        task.Start();
     
        for (int i = 0; i < 10; i++)
        {
            Console.WriteLine("Running in main thread.");
            Thread.Sleep(500);
         }
         
         Console.Read();
    }
    
    如果要往线程里传递参数,Task构造函数提供的重载,可以传入一个object类型的参数:
    Task task = new Task(TaskMethodWithParameter, "Hello world");
    task.Start();
    
    下面是带参的线程方法:
    static void TaskMethodWithParameter(object param)
    {
        for (int i = 0; i < 10; i++)
        {
            Console.WriteLine(String.Format("Running in a task. Parameter: {0}", param));
            Thread.Sleep(500);
        }
    }
    
    2、TaskFactory类
    使用实例化的TaskFactory类,在其中把TaskMethod方法传递给StartNew()方法,就会立即启动任务。
    TaskFactory tf = new TaskFactory();
    tf.StartNew(TaskMethod);
    
    3、Task.Factory属性
    Task类提供了一个Factory静态属性,这个属性返回一个TaskFactory对象。
    Task task = Task.Factory.StartNew(TaskMethod);
    
    
    ///////////////////////////////////////////////////////////////////////////////////
    C#异步编程的实现方式——连续任务
    
    通过任务,可以指定在任务完成后,应开始运行另一个特定任务。任务处理程序或者不带参数或者带一个对象参数,而连续处理程序有一个Task类型的参数。下面先定义两个任务:
    
    static void FirstTaskMethod()
    {
        Console.WriteLine(String.Format("Task {0} is doing something", Task.CurrentId));
        Thread.Sleep(200);
    }
     
    static void SecondTaskMethod(Task task)
    {
        Console.WriteLine("Last task is finished");
        Console.WriteLine(String.Format("Task {0} is doing something", Task.CurrentId));
        Thread.Sleep(200);
    }
    
    连续任务通过在任务上调用ContinueWith()方法来现实:
    static void Main(string[] args)
    {
        Task task1 = new Task(FirstTaskMethod);
        Task task2 = task1.ContinueWith(SecondTaskMethod);
        task1.Start();
     
        for (int i = 0; i < 20; i++)
        {
            Console.WriteLine("Main thread is running");
            Thread.Sleep(200);
        }
     
        Console.Read();
    }
    主线程循环输出字符串到控制台,Task1任务在另外一个线程里运行,FirstTaskMethod执行完继续SecondTaskMethod
    值得注意的是,在一个任务结束时,可以启动多个任务,也就是说,任务的连接可以像一个树结构那样,如下代码:
    
    Task task1 = new Task(FirstTaskMethod);
    Task task2 = task1.ContinueWith(SecondTaskMethod);
    Task task3 = task1.ContinueWith(SecondTaskMethod);
    Task task4 = task2.ContinueWith(SecondTaskMethod);
    Task task5 = task2.ContinueWith(SecondTaskMethod);
    无论前一个任务是如何结束的,后面的连续任务总是在前一个任务结束时启动。
    TaskContinuationOptions枚举提供了OnlyOnFaulted,NotOnFaulted,OnlyOnCanceled,
    NotOnCanceled,OnlyOnRunToCompletion几个选项。我们可以指定只有当前一个任务成功结束时才启动:
    
    Task task5 = task2.ContinueWith(SecondTaskMethod, TaskContinuationOptions.OnlyOnRanToCompletion);
    
    
    ///////////////////////////////////////////////////////////////////////////////////
    C#异步编程的实现方式——层次任务
    
    任务也可以构成一个层次结构。一个任务启动一个新任务时,就启动了一个层次结构。
    下面的代码段在父任务内部新建一个任务。创建子任务的代码与创建父任务的代码相同,
    唯一的区别是这个任务从另一个任务内部创建:
    
    static void Main(string[] args)
    {
        Task parentTask = new Task(ParentTask);
        parentTask.Start();
     
        Console.Read();
    }
     
    static void ParentTask()
    {
        Console.WriteLine("Parent task is starting");
    	Task childTask= new Task(ChildTask,TaskCreationOptions.AttachedToParent);
        childTask.Start();
        Thread.Sleep(2000);
        Console.WriteLine("Parent task is finished");
    }
     
    static void ChildTask()
    {
        Console.WriteLine("Child task started");
        Thread.Sleep(4000);
        Console.WriteLine("Child task is finished");
    }
    
    
    ///////////////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////////////
    
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using System.Collections.Generic;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace Ex.RulesTester.Threads
    {
        /// <summary>
        /// Task异步等待所有线程结束通知测试
        /// </summary>
        [TestClass]
        public class TaskAllCompleteTester
        {
            [TestMethod]
            public void TestTaskPoolStatus()
            {
                //运行异步多任务
                TaskTest.RunTask();
                var list = TaskTest.SuccessList;
                bool isAllComplete = false;
                //等待异步通知
                while (!isAllComplete)
                {
                    isAllComplete = TaskTest.IsAllComplete;
                    list = TaskTest.SuccessList;
                }
    
                Assert.IsTrue(true);
            }
            /// <summary>
            /// 对于 task 多任务执行的封装
            /// </summary>
            private class TaskTest
            {
                private static object m_lock = new object();
                public static List<string> SuccessList = new List<string>();
                private static string msg = "";
                public static bool IsFinish = false;
                public static List<Task> TaskList = new List<Task>();
                static bool isAllComplete = false;
                /// <summary>
                /// 标记所有任务是否全部执行完毕
                /// </summary>
                public static bool IsAllComplete
                {
                    get { return isAllComplete; }
                }
    
                private TaskTest()
                {
    
                }
    
                public static void RunTask()
                {
                    //运行5个任务
                    for (int i = 1; i <= 5; i++)
                    {
                        var task = Task.Factory.StartNew(DoTask, i);
                        TaskList.Add(task);
                    }
                    //异步等待所有任务执行完毕
                    Task.Factory.StartNew(x =>
                    {
                        Task.WaitAll(TaskList.ToArray());
                        //标记所有任务运行完成
                        isAllComplete = true;
                    }, null);
                }
                private static void DoTask(object par)
                {
                    Thread.Sleep(int.Parse(par.ToString()) * 1000);
                    lock (m_lock)
                    {
                        SuccessList.Add("Has Completed T" + par.ToString());
                    }
                }
    
            }
        }
    }
    

  • 相关阅读:
    docker指令汇总
    springboot(八) 嵌入式Servlet容器自动配置原理和容器启动原理
    RabbitMQ 消息确认机制
    RabbitMQ 最常用的三大模式
    RabbitMQ 核心概念
    RabbitMQ 之简单队列
    Spring 详解(三)------- SpringMVC拦截器使用
    slf4j 搭配 log4j2 处理日志
    Spring 详解(二)------- AOP关键概念以及两种实现方式
    Spring 详解(一)------- AOP前序
  • 原文地址:https://www.cnblogs.com/smartsmile/p/6234066.html
Copyright © 2020-2023  润新知