(精华)2020年8月12日 C#基础知识点 异步专题(发展史,多线程,多进程,协程,单线程非阻塞)

一:引言

/// .NetFramework1.0就有多线程!
/// 进程:计算机概念,程序运行在服务器占据的所有计算机的资源 
/// 线程:计算机概念,是进程在相应操做时候的一个最小单元,也包括cpu/硬盘/内存  虚拟概念 
/// 进程和线程:包含关系,线程是属于某一个进程的,若是一个进程销毁,线程也就不会存在。 
/// 句柄:描述程序中的某一个最小单元,是一个long数字,操做系统经过这个数字识别应用程序。 
/// 多线程:计算概念,就是某一个进程中,多个线程同时运行;
///  
/// C#中的多线程: 
/// Thread类是C#语言对线程对象一个封装;
/// 
/// 为何能够多线程呢?
/// 
/// 一、Cpu有多个核;能够并行计算;
///    双核四线:这里的线程是模拟核;
/// 
/// 二、cpu分片:某1s的处理能切分红1000份,操做系统调度去相应不一样的任务;
///   从宏观角度来讲:感受就有多个任务在并发执行;
///   从微观角度来讲:一个物理cpu不能在某一刻为某一个任务服务
///   
/// 同步异步:
///     同步方法:发起调用,只有在调用的方法完成之后,才能继续执行一下一行代码,按照顺序执行;
///     诚心请吃饭,我请你吃饭,你说你如今须要忙一下子,我等你,等你忙完了之后,我们一块儿去吃饭。
///     
///     异步方法:发起调用,不等待完成,直接进入下一行代码的执行,启动一个新的线程来完成计算
///     
///     客气一下请人吃饭:我请你吃饭,你说你如今须要忙一下子,我就不等你了,我本身先去吃饭了,你忙完之后,本身去吃饭。

二:同步和异步的比较

#region Sync
        /// <summary>
        /// 同步方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSync_Click(object sender, EventArgs e)
        {
            Console.WriteLine($"****************btnSync_Click Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
            int l = 3;
            int m = 4;
            int n = l + m;
            for (int i = 0; i < 5; i++)
            {
                string name = string.Format($"btnSync_Click_{i}");
                this.DoSomethingLong(name);
            }
            Console.WriteLine($"****************btnSync_Click End {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");

        }
        #endregion

        #region Async
        /// <summary> 
        /// 异步方法:
        /// 一、同步方法卡界面:主线线程(UI线程)忙于计算,无暇他顾 
        /// 异步方法不卡界面:由于异步方法是新启动一个线程去完后计算,主线程闲置
        /// 改善用户体验,winform程序点击某一个按钮,不会卡死界面;
        /// 发短信,发邮件能够交给一个子线程去完成
        /// 
        /// 二、同步方法执行慢:只有一个线程完成计算
        /// 异步方法执行快:多个线程去完成计算
        /// 10000ms 3000ms 快了三倍多
        /// 20000ms 15000ms cpu密集型计算
        /// 资源换性能
        /// 
        /// 三、同步方法有序执行,异步多线程无顺序
        /// 启动无序,线程资源是向操做系统申请的,操做系统有本身的调度策略,因此启动是随机的;
        /// 以上两点得出: 结束也是没有顺序
        /// 
        /// 若是须要控制顺序呢?怎么实现? 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnAsync_Click(object sender, EventArgs e)
        {
            Console.WriteLine($"****************btnAsync_Click Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");

            Action<string> action = this.DoSomethingLong;

            for (int i = 0; i < 5; i++)
            {
                action.BeginInvoke("btnAsync_Click", null, null);
            }

            Console.WriteLine($"****************btnAsync_Click End {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
        }
        #endregion


        #region Private Method
        /// <summary>
        /// 一个比较耗时耗资源的私有方法
        /// </summary>
        /// <param name="name"></param>
        private void DoSomethingLong(string name)
        {
            Console.WriteLine($"****************DoSomethingLong Start {name} {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
            long lResult = 0;
            Thread.Sleep(2000);//线程等待
            Console.WriteLine($"****************DoSomethingLong End {name} {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} {lResult}***************");
        }
        #endregion

        private void btnAsyncAdvanced_Click(object sender, EventArgs e)
        {
             Console.WriteLine($"****************btnAsyncAdvanced_Click Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");

            IAsyncResult asyncResult = null;
            AsyncCallback callback = ar =>
            {

                Thread.Sleep(5000);
                Console.WriteLine($"这里是beginInvoke的第三个参数{ar.AsyncState}");
                Console.WriteLine(object.ReferenceEquals(ar, asyncResult));
                Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy - MM - dd HH: mm:ss.fff")}");
                Console.WriteLine("计算结束");
            };
            {
                //一、回调
                Action<string> action = this.DoSomethingLong;
                //把自定义的参数传入到回调函数中去
                asyncResult = action.BeginInvoke("btnAsyncAdvanced_Click", callback, "八万千米");
                //二、IsCompleted 完成等待 
                {
                    int i = 0;
                while (!asyncResult.IsCompleted)
                {
                    if (i < 9)
                    {
                        Console.WriteLine($"正在玩命为你加载中。。。已经完成{++i * 10}%");
                    }
                    else
                    {
                        Console.WriteLine($"正在玩命为你加载中。。。已经完成99.9999%");
                    }
                    Thread.Sleep(200);
                }

                Console.WriteLine("加载完成。。。");
            }

                //以上两种都是为了等待任务的完成;
                //三、WaitOne等待
                asyncResult.AsyncWaitHandle.WaitOne();//一直等待任务完成
                asyncResult.AsyncWaitHandle.WaitOne(-1);//一直等待任务完成
                asyncResult.AsyncWaitHandle.WaitOne(3000);//最多等待3000ms,若是超时了,就不等待了 

                {
                //四、EndInvoke也能够等待,能够获取委托返回值
                Func<int> func = () =>
                {
                    //Thread.Sleep(5000);
                    return DateTime.Now.Year;
                };
                func.Invoke();
                IAsyncResult asyncResult1 = func.BeginInvoke(ar =>
                  {
                      func.EndInvoke(ar);
                  }, null);

                int iResult = func.EndInvoke(asyncResult1);
                Console.WriteLine(iResult);

            }
            Console.WriteLine($"****************btnAsyncAdvanced_Click End {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} ***************");
        }

三:.NetFramework1.0(Thread)

{
    ParameterizedThreadStart threadStart = ar =>
    {
        this.DoSomethingLong("btnThread_Click");
        Console.WriteLine($"****************btnThread_Click End {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} ***************");
    };
    Thread thread = new Thread(threadStart);
    thread.Start(); //开启一个新线程
}
{
     ThreadStart threadStart = () =>
     {
         Thread.Sleep(5000);
         this.DoSomethingLong("btnThread_Click");
         Console.WriteLine($"****************btnThread_Click End {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} ***************");
     };
     Thread thread = new Thread(threadStart);
     thread.Start(); //开启一个新线程 
     thread.Suspend();// 暂停线程
     thread.Resume();//恢复 没法实时的去暂停或者恢复线程 
     thread.Abort();//终结线程
     Thread.ResetAbort();//都会有延时


     //若是咱们须要等待;
     //一、等待
     while (thread.ThreadState != ThreadState.Stopped)
     {
         Thread.Sleep(200);
     }
     //二、Join等待
     thread.Join();//能够限时等待
     thread.Join(2000); //能够限时等待

     thread.Priority = ThreadPriority.Highest;//设置线程优先级,只是增长他的优先几率;并不能必定的

     thread.IsBackground = true;//为后台线程 进程结束,线程结束了
     thread.IsBackground = false; //前台线程 进程结束后,任务执行完毕之后,线程才结束 
     {
         ThreadStart threadStart1 = () =>
         {
             Console.WriteLine($"****************btnThread_Click End {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} ***************");
             Thread.Sleep(3000);
         };

         Action action = () =>
         {
             Console.WriteLine($"****************btnThread_Click End {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} ***************");

             Thread.Sleep(3000);
         };
         this.ThreadWithCallBack(threadStart1, action); 
     }
     {
         //Thread开启一个新的线程执行任务,如何获取返回结果:
         Func<int> func = () =>
         {
             Thread.Sleep(5000);
             return DateTime.Now.Year;
         };
         Func<int> FuncResult = this.ThreadWithReturn(func);
         int iResult = FuncResult.Invoke();//若是须要获得执行结果,是必需要等待的
     }
 }
 /// <summary>
 /// 开启线程执行委托函数
 /// </summary>
 /// <param name="threadStart"></param>
 /// <param name="actionCallback"></param>
 private void ThreadWithCallBack(ThreadStart threadStart, Action actionCallback)
 {
     ThreadStart threadStart1 = new ThreadStart(() =>
     {
         threadStart.Invoke();
         actionCallback.Invoke();
     });
     Thread thread = new Thread(threadStart1);
     thread.Start();
 }


 /// <summary>
 /// 既要不卡界面,又须要返回结果 
 /// </summary>
 /// <typeparam name="T"></typeparam>
 /// <param name="func"></param>
 /// <returns></returns>
 private Func<T> ThreadWithReturn<T>(Func<T> func)
 {
     T t = default(T);
     ThreadStart threadStart = new ThreadStart(() =>
     {
         t = func.Invoke();
     });
     Thread thread = new Thread(threadStart);
     thread.Start();
     return new Func<T>(() =>
     {
         thread.Join();
         return t;
     });
 }

四:.NetFramework2.0(ThreadPool)

/// <summary>
/// 线程池
/// .NetFramework2.0 
/// 在Thread中对线程的管理须要咱们本身去从操做,在不断的开启线程和销毁中,存在很大的开销,为了让线程能够反复的使用,出现了池化思想!
/// 能够节省资源,线程池还能够控制线程总数量,防止滥用!
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnThreadPool_Click(object sender, EventArgs e)
{
    Console.WriteLine($"****************btnThreadPool_Click Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
    {
        ThreadPool.QueueUserWorkItem(o =>
        {
            Console.WriteLine($"**************** {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
            this.DoSomethingLong("ThreadPool.QueueUserWorkItem1");//开启了一个线程
        }); 
    }
    {
        ThreadPool.QueueUserWorkItem(o =>
        {
            Console.WriteLine($"第二个参数:{o}");
            this.DoSomethingLong("ThreadPool.QueueUserWorkItem1");//开启了一个线程
        }, "Hyl");
    }
    {
        ThreadPool.GetMaxThreads(out int maxWorkerThreads, out int maxCompletionPortThreads);
        ThreadPool.GetMinThreads(out int minWorkerThreads, out int minCompletionPortThreads);

        Console.WriteLine($"当前电脑最大workerThreads={maxWorkerThreads},最大的completionPortThreads={maxCompletionPortThreads}");
        Console.WriteLine($"当前电脑最小workerThreads={minWorkerThreads},最小的completionPortThreads={minCompletionPortThreads}");

        Console.WriteLine("设置线程数量以后:");
        //设置线程数量是全局,线程池是全局,Task,async/awit 都是来自于线程,老师不建议你们随便设置! 
        ThreadPool.SetMaxThreads(2, 2); //这里在设置的时候,数量不能低于本计算机的 核数
        ThreadPool.SetMinThreads(2, 2);

        ThreadPool.GetMaxThreads(out int maxWorkerThreads1, out int maxCompletionPortThreads1);
        ThreadPool.GetMinThreads(out int minWorkerThreads1, out int minCompletionPortThreads1);

        Console.WriteLine($"当前电脑最大workerThreads={maxWorkerThreads1},最大的completionPortThreads={maxCompletionPortThreads1}");
        Console.WriteLine($"当前电脑最小workerThreads={minWorkerThreads1},最小的completionPortThreads={minCompletionPortThreads1}");
    }
    {
        //线程等待:
        //在线程池中,有一个开关式 
        ManualResetEvent manualResetEvent = new ManualResetEvent(false); //开关关闭 
        ThreadPool.QueueUserWorkItem(o =>
        {
            this.DoSomethingLong("btnThreadPool_Click1");
            Thread.Sleep(3000);
            manualResetEvent.Set();// 开关打开
        });
        manualResetEvent.WaitOne();//执行到这儿来的时候,我就等你给我发信号
        Console.WriteLine("计算完成");
    }
    {
        ThreadPool.SetMaxThreads(8, 8);//设置了最大的线程数量
        ManualResetEvent manualResetEvent = new ManualResetEvent(false); //开关关闭 
        for (int i = 0; i < 10; i++)
        {
            int k = i;
            ThreadPool.QueueUserWorkItem(t =>
               {
                   Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
                   if (k == 9)
                   {
                       manualResetEvent.Set();
                   }
                   else
                   {
                       manualResetEvent.WaitOne();
                   }

               });

        }
        if (manualResetEvent.WaitOne())
        {
            Console.WriteLine("执行成功!");
        }
    }
    Console.WriteLine($"****************btnThreadPool_Click End {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} ***************");
}

五:.NetFramework3.0(Task)

/// <summary>
/// Task 是.NetFramework3.0出现的。提供了很是多的Api
/// Task里面的线程是来自于线程池!
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btntask_Click(object sender, EventArgs e)
{
    Console.WriteLine($"****************btnThreadPool_Click Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
    {
        Task task = new Task(() =>
        {
            this.DoSomethingLong("btntask_Click1");
        });
        task.Start();//开启了一个新的线程
    }
    {
        Task.Run(() =>
        {
            this.DoSomethingLong("btntask_Click2");
        });
    }
    {
        //TaskFactory taskFactory = new TaskFactory();
        TaskFactory taskFactory = Task.Factory;
        taskFactory.StartNew(() =>
        {
            this.DoSomethingLong("btntask_Click3");
        });
    }
    {
        Thread thread = new Thread(() => { Console.WriteLine("开启了一个新线程"); });
        thread.Start();
        ThreadPool.QueueUserWorkItem(o => { Console.WriteLine("开启了一个新线程"); });
    }
    {
        {
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            Thread.Sleep(2000);
            stopwatch.Stop();
            Console.WriteLine($"{stopwatch.ElapsedMilliseconds}");
        }
        {
            // Task.Delay 出现于4.5版本
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            Task task = Task.Delay(2000).ContinueWith(t =>  //任务在2000ms 之后执行
            {
                stopwatch.Stop();
                Console.WriteLine($"{stopwatch.ElapsedMilliseconds}");
                Console.WriteLine("回调已完成");
            });
        }
    }
    {
        //能够并发执行的时候就可使用多线程

        List<Task> tasksList = new List<Task>();

        TaskFactory taskFactory = new TaskFactory();

        tasksList.Add(taskFactory.StartNew(() => { this.Coding("001", "系统管理"); }));
        tasksList.Add(taskFactory.StartNew(() => { this.Coding("002", "部门管理"); }));
        tasksList.Add(taskFactory.StartNew(() => { this.Coding("003", "客户管理"); }));
        tasksList.Add(taskFactory.StartNew(() => { this.Coding("004", "接口管理"); }));
        tasksList.Add(taskFactory.StartNew(() => { this.Coding("005", "写Api"); }));

        //若是有一个同窗完成了某一个模块,老师就须要准备环境!
        // 等待某一个线程执行完毕之后 继续日后执行
        Task.WaitAny(tasksList.ToArray());

        Task.WaitAll(tasksList.ToArray()); //阻塞主线程
    }

    Console.WriteLine($"****************btnThreadPool_Click End {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} ***************");
}

六:.NetFramework4.5(Parallel )

/// <summary>
/// Parallel 对Task进一步进行了封装 .Netframework 4.5版本出来
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnParallel_Click(object sender, EventArgs e)
{
    Console.WriteLine($"**************** btnParallel_Click Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} ***************");
    {

        //多线程中控制执行顺序,一直是一个难题,使用Parallel能够控制线程的执行顺序。
        //Parallel并发执行了五个委托,开启了新线程,主线程参与计算,界面会阻塞
        // Task WaitAll + 主线程
        Parallel.Invoke(() => { this.DoSomethingLong("btnParallel_Click_1"); },
            () => { this.DoSomethingLong("btnParallel_Click_2"); },
            () => { this.DoSomethingLong("btnParallel_Click_3"); },
            () => { this.DoSomethingLong("btnParallel_Click_4"); },
            () => { this.DoSomethingLong("btnParallel_Click_5"); });
    }
    {
        ParallelOptions parallelOptions = new ParallelOptions();
        parallelOptions.MaxDegreeOfParallelism = 2;//最大并行数
        Parallel.For(0, 10, parallelOptions, t => this.DoSomethingLong($"btnParallel_Click_{t}"));
    }
    {
        ////控制线程数量
        ParallelOptions parallelOptions = new ParallelOptions();
        parallelOptions.MaxDegreeOfParallelism = 2;  //控制线程的最大数量
        //控制执行数量
        Parallel.ForEach(new int[] { 12, 13, 14, 15, 16, 17 }, parallelOptions, t => this.DoSomethingLong($"btnParallel_Click_{t}"));
    }
    Console.WriteLine($"**************** btnParallel_Click End {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} ***************");
}

七:多线程异常处理和异常取消

/// <summary>
/// 多线程异常处理
/// 线程取消
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnThreadCore_Click(object sender, EventArgs e)
{
    Console.WriteLine($"**************** btnThreadCore_Click Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} ***************");

    //多线程中若是某一个线程异常了,就会终结当前线程;对其余的线程是没有影响的;

    //多线程中的异常去哪儿了? 
    //被吞掉了
    #region 多线程异常处理
    {
        Thread thread = new Thread('执行方法');
        thread.Abort();
        try
        {
            List<Task> taskList = new List<Task>();
            for (int i = 0; i < 100; i++)
            {
                string name = $"btnThreadCore_Click_{i}";
                int k = i;
                taskList.Add(Task.Run(() =>
                {
                    if (k == 5)
                    {
                        throw new Exception($"{name} 异常了");
                    }
                    else if (k == 6)
                    {
                        throw new Exception($"{name} 异常了");
                    }
                    else if (k == 10)
                    {
                        throw new Exception($"{name} 异常了");
                    }
                    Console.WriteLine($"this is {name} Ok!");
                }));
            };
            Task.WaitAll(taskList.ToArray());
        }
        catch (AggregateException aex)  //能够有多个Catch 在匹配异常类型的时候,先具体,而后在寻找父类
        {
            foreach (var exception in aex.InnerExceptions)
            {
                Console.WriteLine(exception.Message);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
            throw;
        }
        //在实际的工做中,每每有不少场景是若是发生异常以后,其余的线程就须要取消,再也不继续往下执行;问题就是如何取消线程;
    }
    #endregion
    #region 线程取消
    {
        //全局变量 
        //bool IsOk = true;
        CancellationTokenSource cts = new CancellationTokenSource();// 通知式的
        try
        { 
            List<Task> taskList = new List<Task>();
            for (int i = 0; i < 100; i++)
            {
                string name = $"btnThreadCore_Click_{i}";
                int k = i;
                taskList.Add(Task.Run(() =>
                {
                    if (k == 5)
                    { 
                        throw new Exception($"{name} 异常了");
                    }
                    if (!cts.IsCancellationRequested)//是否取消
                    {
                        Console.WriteLine($"this is {name} Ok!");
                    }
                    else
                    {
                        Console.WriteLine($"this is {name} Stop!");
                    } 
                }));
            };
            Task.WaitAll(taskList.ToArray());
        }
        catch (AggregateException aex)  //能够有多个Catch 在匹配异常类型的时候,先具体,而后在寻找父类
        {
            cts.Cancel(); //执行该方法之后,IsCancellationRequested会被指定为false
            foreach (var exception in aex.InnerExceptions)
            {
                Console.WriteLine(exception.Message);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
            throw;
        } 
    }
    #endregion
    Console.WriteLine($"**************** btnThreadCore_Click End {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} ***************");
}

八:多线程安全问题

private static readonly object Obj_Lock = new object();
//1 Lock;不能锁null,不建议你们锁String; 锁 this
//使用锁:private static readonly object Obj_Lock = new object()
//锁的做用:排他
//2 线程安全集合 
// System.Collections.Concurrent.ConcurrentStack 基于线程安全 
//3 数据分拆,避免多个线程操做同一堆数据,安全又高效率

//保证线程安全不会使用同一个变量
for (int i = 0; i < 100000; i++)
{
	this.NumOne += 1;
}

for (int i = 0; i < 100000; i++)
{
	Task.Run(() =>
	{
		try
		{
		lock (Obj_Lock )//能够 避免多线程并发,若是锁住之后,其实这里跟单线程 基本上没啥区别;
			{
				this.NumTow += 1;
			}
		}
		catch (Exception)
		{
			throw;
		}

	});
}
/// <summary>
/// new Random().Next(1, 100); 多线程同时执行结果很高几率相同,
/// 是用的当前时间为seed,时间相同结果相同
/// 
/// 解决随机数重复问题
/// 同时模拟远程请求的随机延时
/// </summary>
public class RandomHelper
{
    /// <summary>
    /// 随机获取数字并等待1~2s
    /// </summary>
    /// <returns></returns>
    public int GetRandomNumberDelay(int min, int max)
    {
        Thread.Sleep(this.GetRandomNumber(500, 1000));//随机休息一下
        return this.GetRandomNumber(min, max);
    }


    /// <summary>
    /// 获取随机数,解决重复问题
    /// </summary>
    /// <param name="min"></param>
    /// <param name="max"></param>
    /// <returns></returns>
    public int GetRandomNumber(int min, int max)
    {
        Guid guid = Guid.NewGuid();//每次都是全新的ID
        string sGuid = guid.ToString();
        int seed = DateTime.Now.Millisecond;
        for (int i = 0; i < sGuid.Length; i++)
        {
            switch (sGuid[i])
            {
                case 'a':
                case 'b':
                case 'c':
                case 'd':
                case 'e':
                case 'f':
                case 'g':
                    seed = seed + 1;
                    break;
                case 'h':
                case 'i':
                case 'j':
                case 'k':
                case 'l':
                case 'm':
                case 'n':
                    seed = seed + 2;
                    break;
                case 'o':
                case 'p':
                case 'q':
                case 'r':
                case 's':
                case 't':
                    seed = seed + 3;
                    break;
                case 'u':
                case 'v':
                case 'w':
                case 'x':
                case 'y':
                case 'z':
                    seed = seed + 3;
                    break;
                default:
                    seed = seed + 4;
                    break;
            }
        }
        Random random = new Random(seed);
        return random.Next(min, max);
    }
}

九:最终版(async/await)

public class AwaitAsyncClass
{
    public async static void TestShow()
    {
        Test();
    }

    private async static Task Test()
    {
        Console.WriteLine($"当前主线程id={Thread.CurrentThread.ManagedThreadId.ToString("00")}");
        {
            Task t = NoReturnTask();
            Console.WriteLine($"Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
            t.Wait();//主线程等待Task的完成 阻塞的
            await t;//await后的代码会由线程池的线程执行 非阻塞
        }
        {
            Task<long> t = SumAsync();
            Console.WriteLine($"Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
            long lResult = t.Result;//访问result 主线程等待Task的完成
            t.Wait();//等价于上一行
        }
        {
            Task<int> t = SumFactory();
            Console.WriteLine($"Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
            long lResult = t.Result;//没有await和async 普通的task
            t.Wait();
        }
        Console.WriteLine($"Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
        Console.Read();
    }

    /// <summary>
    /// 无返回值 async Task == async void
    /// Task和Task<T>可以使用await, Task.WhenAny, Task.WhenAll等方式组合使用。Async Void 不行
    /// </summary>
    /// <returns></returns>
    private static async Task NoReturnTask()
    {
        //这里仍是主线程的id
        Console.WriteLine($"NoReturnTask Sleep before await,ThreadId={Thread.CurrentThread.ManagedThreadId}");

        Task task = Task.Run(() =>
        {
            Console.WriteLine($"NoReturnTask Sleep3000 before,ThreadId={Thread.CurrentThread.ManagedThreadId}");
            Thread.Sleep(3000);
            Console.WriteLine($"NoReturnTask Sleep3000 after,ThreadId={Thread.CurrentThread.ManagedThreadId}");
        });
        await task;
        Console.WriteLine($"NoReturnTask Sleep after await,ThreadId={Thread.CurrentThread.ManagedThreadId}");
    }

    /// <summary>
    /// 带返回值的Task 
    /// 要使用返回值就必定要等子线程计算完毕
    /// </summary>
    /// <returns>async 就只返回long</returns>
    private static async Task<long> SumAsync()
    {
        Console.WriteLine($"SumAsync 111 start ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
        long result = 0;

        await Task.Run(() =>
        {
            for (int k = 0; k < 10; k++)
            {
                Console.WriteLine($"SumAsync {k} await Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
                Thread.Sleep(1000);
            }
            for (long i = 0; i < 999_999_999; i++)
            {
                result += i;
            }
        });

        Console.WriteLine($"SumFactory 111 end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
        await Task.Run(() =>
        {
            for (int k = 0; k < 10; k++)
            {
                Console.WriteLine($"SumAsync {k} await Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
                Thread.Sleep(1000);
            }
            for (long i = 0; i < 999999999; i++)
            {
                result += i;
            }
        });

        Console.WriteLine($"SumFactory 111 end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");

        await Task.Run(() =>
        {
            for (int k = 0; k < 10; k++)
            {
                Console.WriteLine($"SumAsync {k} await Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
                Thread.Sleep(1000);
            }

            for (long i = 0; i < 999999999; i++)
            {
                result += i;
            }
        });

        Console.WriteLine($"SumFactory 111 end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");

        return result;
    }

    /// <summary>
    /// 真的返回Task 不是async 
    /// 
    /// 要使用返回值就必定要等子线程计算完毕
    /// </summary>
    /// <returns>没有async Task</returns>
    private static Task<int> SumFactory()
    {
        Console.WriteLine($"SumFactory 111 start ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
        TaskFactory taskFactory = new TaskFactory();
        Task<int> iResult = taskFactory.StartNew<int>(() =>
        {
            Thread.Sleep(3000);
            Console.WriteLine($"SumFactory 123 Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
            return 123;
        });
        //Console.WriteLine($"This is {iResult.Result}");
        Console.WriteLine($"SumFactory 111 end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
        return iResult;
    }
}