public void testStopTaskWait()
        {
            //2020/7/17 9:47:55 before cts.cancel in thread 10 and no task       // step 1
            //执行cts.Cancel()                                                   // step 2
            //2020/7/17 9:47:55 cancel token reg - 03 in thread 10 and no task   // step 3
            //2020/7/17 9:47:55 cancel token reg - 02 in thread 10 and no task   // step 4
            //2020/7/17 9:47:55 cancel token reg - 01 in thread 10 and no task   // step 5
            //Delay地方捕捉到异常                                                 // step 6
            //2020/7/17 9:47:55 after delay in thread 13 and no task             // step 7
            CancellationTokenSource cts = new CancellationTokenSource();

            //这些注册的delegate,将在执行Cancel的时候调用到
            cts.Token.Register(() => { ThreadEval_Util.TraceThreadAndTask("cancel token reg - 01"); }); // step 5
            cts.Token.Register(() => { ThreadEval_Util.TraceThreadAndTask("cancel token reg - 02"); }); // step 4
            cts.Token.Register(() => { ThreadEval_Util.TraceThreadAndTask("cancel token reg - 03"); }); // step 3

            ThreadPool.QueueUserWorkItem(state => {
                ThreadEval_Util.TraceThreadAndTask("before cts.cancel"); // step 1
                Thread.Sleep(10);
                cts.Cancel();                                            // step 2
            });

            //System.AggregateException : One or more errors occurred. (A task was canceled.)
            //  ----> System.Threading.Tasks.TaskCanceledException : A task was canceled.
            Assert.Throws <AggregateException>(() => Task.Delay(100, cts.Token).Wait()); // step 6

            ThreadEval_Util.TraceThreadAndTask("after delay");                           // step 7
        }
        public void testGreetingClient()
        {
            //下面是这个过程的输出
            //2020.07.17 10:11:55:536 testGreetingClient enter in thread 13 and no task
            //2020.07.17 10:11:55:538 callGreetingClientAsync enter in thread 13 and no task
            //2020.07.17 10:11:55:539 running GreetingAsync in thread 11 and task 1
            //2020.07.17 10:11:55:539 running Greeting in thread 11 and task 1
            //2020.07.17 10:11:55:539 testGreetingClient got Task<String> greetingResult, and next to get greetingResult.Result in thread 13 and no task
            //这里有个500毫秒的gap(当时Greeting方法正在blocking wait)
            //2020.07.17 10:11:56:050 callGreetingClientAsync done in thread 11 and no task
            //2020.07.17 10:11:56:050 testGreetingClient done - got greetingResult.Result:Hello, HanMeiMei in thread 13 and no task

            ThirdPartyAsyncSimulator greetingClient = new ThirdPartyAsyncSimulator();

            //线程A - 调用者当前线程
            ThreadEval_Util.TraceThreadAndTask($"{nameof(testGreetingClient)} enter");
            Task <String> greetingResult = callGreetingClientAsync();

            ThreadEval_Util.TraceThreadAndTask($"{nameof(testGreetingClient)} got Task<String> greetingResult, and next to get greetingResult.Result");

            //线程A - 前面都很快,而执行这个获取task结果卡住了,因为结果还没有出来
            String greetingResultStr = greetingResult.Result;

            //线程A - 这里线程没变
            ThreadEval_Util.TraceThreadAndTask($"{nameof(testGreetingClient)} done - got greetingResult.Result:{greetingResultStr}");
        }
        //尝试过去掉async/await,结果没啥两样。加上他们是为了让代码看起来更一致
        private async Task <String> forgedTaskFromResultAsync()
        {
            ThreadEval_Util.TraceThreadAndTask("forgedTaskFromResultAsync - before await");
            var result = await Task.FromResult(longRunTask());

            ThreadEval_Util.TraceThreadAndTask("forgedTaskFromResultAsync - after await");
            return(result);
        }
            public Task <String> GreetingAsync(String name)
            {
                Task <String> result = Task.Run <String>(() =>
                {
                    ThreadEval_Util.TraceThreadAndTask($"running {nameof(GreetingAsync)}");
                    return(Greeting(name));
                });

                return(result);
            }
        /**
         *
         * 这里给出了1个使用httpclient async方法的例子(其实也没看出来节省时间!因为最外部调用方法还是要等待)
         * 注释掉了[Test]是因为其有外部依赖(baidu.com). 这个调用过程用上面的Greeting完全是一致的
         *
         */
        //[Test]
        public void testHttpClient()
        {
            //线程A
            ThreadEval_Util.TraceThreadAndTask("{nameof(testHttpClient)} enter");
            Task <int> lengthTask = GetPageLengthAsync("http://www.baidu.com");

            //在async方法运行的时候,当前task已经返回到这里了,但是如果这里获取结果的话,则继续等待直到async方法执行完毕
            //也就是说,从这儿的角度,其并没有加快什么
            //除非当前这里的业务逻辑不在乎task执行结果(我是说这一行不在乎执行结果,执行结果可以在GetPageLengthAsync里的线程B中做某种处理)································································································································································································································································································································································································································································································································································································································································································································································································································
            Console.WriteLine(lengthTask.Result);

            //线程A - 这里线程没变
            ThreadEval_Util.TraceThreadAndTask("{nameof(testHttpClient)} done");
        }
        public async Task testTaskAsyncDelay()
        {
            //2020.07.17 10:09:59:294 before delay in thread 13 and no task           - step 1 - 调用者线程
            //调用者碰到await直接返回,继续执行其他工作(这里的调用者实际上为NUnit测试框架) - step 2
            //2020.07.17 10:09:59:394 after delay in thread 9 and no task             - step 3 - 100毫秒之后,新线程继续执行

            Int32 delayInterval = 100;

            //线程A
            ThreadEval_Util.TraceThreadAndTask("before delay"); //step 1
            //线程A执行到await之后,立马返回
            await Task.Delay(delayInterval);                    //step 2

            //过delayInterval毫秒之后,线程B继续执行下面逻辑
            //线程B
            ThreadEval_Util.TraceThreadAndTask("after delay");  //step 3
        }
        public void testTaskFromResult()
        {
            //全部都是在同步调用,只不过可以融入到async调用的moshi
            //2020.07.17 22:11:27:820 forgedTaskFromResultAsync - before await in thread 13 and no task
            //2020.07.17 22:11:27:822 longRunTask in thread 13 and no task
            //2020.07.17 22:11:30:825 forgedTaskFromResultAsync - after await in thread 13 and no task
            //2020.07.17 22:11:30:825 task got in thread 13 and no task
            //2020.07.17 22:11:30:825 task result got in thread 13 and no task

            var task = forgedTaskFromResultAsync();

            ThreadEval_Util.TraceThreadAndTask("task got");

            var result = task.Result;

            ThreadEval_Util.TraceThreadAndTask("task result got");
        }
        static async Task <int> GetPageLengthAsync(string url)
        {
            using (HttpClient client = new HttpClient()) {
                //线程A
                ThreadEval_Util.TraceThreadAndTask("{nameof(GetPageLengthAsync)} enter");
                Task <String> fetchTextTask = client.GetStringAsync(url);

                //代码执行到这里方法就返回了。这个耗时的client.GetStringAsync(url)将在
                //<=====这个await的magic之处在于前后的线程变了
                int length = (await fetchTextTask).Length;

                //线程B 《=== 不再是线程A了!!!!
                ThreadEval_Util.TraceThreadAndTask("{nameof(GetPageLengthAsync)} done");

                //注意,函数返回类型为Task<int>, 但是我们这里要返回int
                return(length);
            }
        }
        public async Task <String> callGreetingClientAsync()
        {
            ThirdPartyAsyncSimulator greetingClient = new ThirdPartyAsyncSimulator();

            //线程A - 就是调用者所在的线程
            ThreadEval_Util.TraceThreadAndTask($"{nameof(callGreetingClientAsync)} enter");
            Task <String> greetingResult = greetingClient.GreetingAsync("HanMeiMei");

            //一旦开始await,这个方法就返回了。调用方法立马得到了Task<String>的结果
            //String greetingResultStr = await greetingResult;

            //这里使用await greetingResult与 await greetingResult.ConfigureAwait(false)是一样的
            //note:但是如果是UI程序,或者asp.net则不一样
            //使用ConfigureAwait(false)的目的是让醒来后的线程可以是随意一个线程池中的线程
            //见本类开头更多总结
            String greetingResultStr = await greetingResult.ConfigureAwait(false);

            //线程B - await之后,task执行之后,处理执行结果是其他线程(不再保证是进入是的线程A)
            ThreadEval_Util.TraceThreadAndTask($"{nameof(callGreetingClientAsync)} done");
            return(greetingResultStr);
        }
        public void testResetEvent()
        {
            //ThreadEval_QueueUserWorkItem::testBasicTaskExecution中,使用了ManualResetEvent

            //注意:如果在Wait之前就发送了信号by Set(),也没关系
            //下面就是证明这个的, WaitOne执行的时候,Set已经执行完了。WaitOne还是顺利的继续执行
            //false:not signaled, 就是需要等待一个新信号才能执行的意思,就是执行WaitOne的时候会block的意思
            //true:signaled, 直接WaitOne就能返回了
            ManualResetEvent mre = new ManualResetEvent(false);

            ThreadPool.QueueUserWorkItem(state => {
                Thread.Sleep(5);
                ThreadEval_Util.TraceThreadAndTask("002 before set");
                mre.Set();
            });
            Thread.Sleep(1000);
            ThreadEval_Util.TraceThreadAndTask("002 before wait");
            for (int i = 0; i < 5; i++)
            {
                //因为没有执行Reset,其一直是signaled状态,所以WaitOne一直可以返回
                mre.WaitOne(); //很可惜没有等待时间超时设置
            }
            ThreadEval_Util.TraceThreadAndTask("003 got signal");
        }
 private String longRunTask()
 {
     ThreadEval_Util.TraceThreadAndTask("longRunTask");
     Task.Delay(3000).Wait();
     return("abc");
 }
        public void testParallelFor_3delegates()
        {
            var nums = Enumerable.Range(1, 99);

            //ForEach<TSource, TLocal>
            //- TSource: 顾名思义,就是输入数据的类型
            //- TLocal是第一个LocalInit方法返回值。该值在整个上下文中使用
            //  - 之后,其被传入body方法中(最后的那个参数)
            //    - 特别注意:body中调用的方法也要返回该类型
            //  - 最后LocalFinally方法的输入参数类型就是它,值将一路传递下来
            //
            //- 特别注意: 该方法还有更多参数(譬如增加option),参考文档
            //
            //, ,

            //如何Cancel,看这连接https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/how-to-cancel-a-parallel-for-or-foreach-loop
            ParallelOptions         options = new ParallelOptions();
            CancellationTokenSource cts     = new CancellationTokenSource();

            options.CancellationToken = cts.Token;
            //cts.Cancel();外部线程执行这个就cancel了
            ParallelLoopResult result = Parallel.ForEach <Int32, Int32>(
                //IEnumerable<TSource> source
                nums,
                options,
                //特别注意:每个线程运行一次
                //Func<TLocal> localInit - 输入值:empty,返回值TLocal的方法
                () =>
            {
                ThreadEval_Util.TraceThreadAndTask("localInit");
                return(0);
            },

                //Func<TSource, ParallelLoopState, long, TLocal, TLocal> body - 输入值:TSource, ParallelLoopState, long, TLocal,返回值:TLocal
                //最后一个输入参数:taskLocalTotal 是从localInit中传过来的,可以在body方法中更新它
                (i, loopState, index, taskLocalTotal) => {
                //注意:stop/break都不会从当前方法返回,当前方法还会继续执行完
                //但是新的iteration大概率不会继续开始,这是有Parallel框架来判断的
                //Stop
                ThreadEval_Util.TraceThreadAndTask($"004-body:{i}-{index} before stop");

                //应该用if(options.CancellationToken.IsCancellationRequested),外部调用
                //可以使用token.ThrowIfCancellationRequested(), 不过Parallel外部要捕捉异常
                //参考 https://stackoverflow.com/questions/8818203/what-is-difference-between-loopstate-break-loopstate-stop-and-cancellationt
                //这里为了测试,直接比较i>10
                if (i > 10)
                {
                    loopState.Stop();
                    //loopState.Break();
                    ThreadEval_Util.TraceThreadAndTask($"003-body:{i}-{index} stop here");
                }
                ThreadEval_Util.TraceThreadAndTask($"003-body:{i}-{index} after stop");

                Thread.Sleep(100);

                //loopState.Stop();
                return(DoWork(i));
            },

                //特别注意:每个线程运行一次
                //Action<TLocal> localFinally - 输入值:TLocal(即talksLocalTotal), 返回值:empty
                //talksLocalTotal是从body中传过来的
                talksLocalTotal =>
            {
                ThreadEval_Util.TraceThreadAndTask("localFinally");
            }
                );

            Console.WriteLine($"result.LowestBreakIteration:{result.LowestBreakIteration.ToString()}");
        }
        public void testParallelForOfAsync()
        {
            //2020.07.17 12:12:48:143 S 3 in thread 14 and task 4
            //2020.07.17 12:12:48:143 S 1 in thread 11 and task 2
            //2020.07.17 12:12:48:143 S 4 in thread 15 and task 5
            //2020.07.17 12:12:48:143 S 2 in thread 6 and task 3
            //2020.07.17 12:12:48:143 S 0 in thread 13 and task 1
            //2020.07.17 12:12:48:144 S 6 in thread 18 and task 7
            //2020.07.17 12:12:48:143 S 5 in thread 16 and task 6
            //2020.07.17 12:12:48:144 S 7 in thread 17 and task 8
            //2020.07.17 12:12:49:029 E 7 in thread 17 and task 8
            //2020.07.17 12:12:49:029 E 5 in thread 16 and task 6
            //2020.07.17 12:12:49:029 E 6 in thread 18 and task 7
            //2020.07.17 12:12:49:029 E 0 in thread 13 and task 1
            //2020.07.17 12:12:49:029 S 8 in thread 19 and task 9
            //2020.07.17 12:12:49:029 E 4 in thread 15 and task 5
            //2020.07.17 12:12:49:029 S 9 in thread 13 and task 1
            //2020.07.17 12:12:49:029 E 1 in thread 11 and task 2
            //2020.07.17 12:12:49:029 E 3 in thread 14 and task 4
            //2020.07.17 12:12:49:029 E 2 in thread 6 and task 3
            //2020.07.17 12:12:49:234 E 9 in thread 13 and task 1
            //2020.07.17 12:12:49:234 E 8 in thread 19 and task 9
            //2020.07.17 12:12:49:234 Completed - WITHOUT async/with - True in thread 13 and no task
            //这是没有async/await的情况,用于对比
            //可以看到S/E所使用的线程是一致是一样的;还可以看到这个Delay的时间不是很准确,我要delay200毫秒,而这里显示达到了900毫秒左右。
            ParallelLoopResult result1 = Parallel.For(0, 10, i =>
            {
                ThreadEval_Util.TraceThreadAndTask($"S {i}");
                Task.Delay(200).Wait();
                ThreadEval_Util.TraceThreadAndTask($"E {i}");
            });

            ThreadEval_Util.TraceThreadAndTask($"Completed - WITHOUT async/with - {result1.IsCompleted}");

            //2020.07.17 12:12:49:236 S 0 in thread 13 and task 10
            //2020.07.17 12:12:49:236 S 6 in thread 14 and task 11
            //2020.07.17 12:12:49:236 S 7 in thread 11 and task 12
            //2020.07.17 12:12:49:236 S 2 in thread 19 and task 13
            //2020.07.17 12:12:49:236 S 8 in thread 18 and task 14
            //2020.07.17 12:12:49:236 S 1 in thread 17 and task 15
            //2020.07.17 12:12:49:236 S 3 in thread 16 and task 16
            //2020.07.17 12:12:49:236 S 4 in thread 15 and task 17
            //2020.07.17 12:12:49:236 S 5 in thread 6 and task 18
            //2020.07.17 12:12:49:238 S 9 in thread 13 and task 10
            //2020.07.17 12:12:49:239 Completed - WITH async/with - True in thread 13 and no task
            //2020.07.17 12:12:49:429 E 9 in thread 6 and no task
            //2020.07.17 12:12:49:429 E 3 in thread 11 and no task
            //2020.07.17 12:12:49:429 E 8 in thread 16 and no task
            //2020.07.17 12:12:49:429 E 1 in thread 18 and no task
            //2020.07.17 12:12:49:429 E 4 in thread 17 and no task
            //2020.07.17 12:12:49:429 E 7 in thread 14 and no task
            //2020.07.17 12:12:49:429 E 5 in thread 19 and no task
            //2020.07.17 12:12:49:429 E 2 in thread 15 and no task
            //2020.07.17 12:12:49:429 E 0 in thread 11 and no task
            //2020.07.17 12:12:49:429 E 6 in thread 19 and no task
            //1. 这里可以看到,S/E所对应的线程是不同的
            //2. Parallel.For方法直接返回了(没有等Delay执行完成 - Completed直接打印了)
            //   过了一会儿,await完成后其他线程把await后的结果执行一遍
            ParallelLoopResult result2 = Parallel.For(0, 10, async i =>
            {
                ThreadEval_Util.TraceThreadAndTask($"S {i}");
                await Task.Delay(200);
                ThreadEval_Util.TraceThreadAndTask($"E {i}");
            });

            ThreadEval_Util.TraceThreadAndTask($"Completed - WITH async/with - {result1.IsCompleted}");
            //下面这个Sleep是有必要的,因为使用了async之后,Parallel调用直接返回(碰到await就返回了),不等待Delay。
            //如果不加这个Sleep,测试case就直接完成了,则后续的ThreadEval_Util.TraceThreadAndTask($"E {i}");无法打印了。
            Thread.Sleep(250);
        }
 private String Greeting(String name)
 {
     ThreadEval_Util.TraceThreadAndTask($"running {nameof(Greeting)}");
     Task.Delay(500).Wait();
     return($"Hello, {name}");
 }