任务---内部揭秘

1,Task对象都有一组字段,这些字段构成了任务的状态:

id----任务的唯一标识

可以使用 Task.CurrentId 静态属性来查询 当前正在调试的代码的ID.

Status:

Created:任务显示创建

WaitingForActivation:任务通过ContinueWith函数创建.会自动开始

WaitingToRan,任务正在调度,但是未执行

Running,任务正在执行

WaitingForChildrenToComplete:正在等待其子进程完成后才能完成.

(设置TaskCreationOption.AttachedToParent)

最终是以下三个状态之一

RanToCompletion

Canceled

Faulted

2,TaskFactory

 public static void TaskFactory()
        {
            Task parent = new Task(() =>
            {
                var cts = new CancellationTokenSource();
                var tf = new TaskFactory<Int32>(cts.Token, TaskCreationOptions.AttachedToParent, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);

                // This tasks creates and starts 3 child tasks
                var childTasks = new[] {
            tf.StartNew(() => Sum(cts.Token, 10000)),
            tf.StartNew(() => Sum(cts.Token, 20000)),
            tf.StartNew(() => Sum(cts.Token, Int32.MaxValue))  // Too big, throws OverflowException
         };

                // If any of the child tasks throw, cancel the rest of them
                for (Int32 task = 0; task < childTasks.Length; task++)
                    childTasks[task].ContinueWith(t => cts.Cancel(), TaskContinuationOptions.OnlyOnFaulted);

                // When all children are done, get the maximum value returned from the non-faulting/canceled tasks
                // Then pass the maximum value to another task which displays the maximum result
                tf.ContinueWhenAll(childTasks,
                   completedTasks => completedTasks.Where(t => !t.IsFaulted && !t.IsCanceled).Max(t => t.Result),
                   CancellationToken.None)
                   .ContinueWith(t => Console.WriteLine("The maximum is: " + t.Result),
                      TaskContinuationOptions.ExecuteSynchronously).Wait(); // Wait is for testing only
            });

            // When the children are done, show any unhandled exceptions too
            parent.ContinueWith(p =>
            {
                // I put all this text in a StringBuilder and call Console.WrteLine just once because this task 
                // could execute concurrently with the task above & I don't want the tasks' output interspersed
                StringBuilder sb = new StringBuilder("The following exception(s) occurred:" + Environment.NewLine);
                foreach (var e in p.Exception.Flatten().InnerExceptions)
                    sb.AppendLine("   " + e.GetType().ToString());
                Console.WriteLine(sb.ToString());
            }, TaskContinuationOptions.OnlyOnFaulted);

            // Start the parent Task so it can start its children
            parent.Start();

        }

        1,创建了一个任务工程,所有的子任务都是以相同方式配置.startNew 或者continuewith 的任务.都视为 TaskFactory的子任务.

      注意,TaskFactory返回一个任务数组.

        2,配置中,表示所有的子任务的父任务都是parent,包括continueWhenAll之类的.

       3,当调用cts.cancel()的时候,注意,为了不让后面的几个continueWhenAll函数取消调用 的 ConcellationToken.None来保证该

Continue不被取消(因为在TaskFactory里面设置了取消,如果默认的话,这个Continue会被取消掉).

       4,AttachParent 和 ExecuteSynchronously()的区别.

         前者一般实在线程创建的时候,表示父线程必须要等待子线程全部完成后才算完成.

         后者表达了该线程的延续任务(ContinueWith)任务,在本来任务的线程上执行就是在同一个线程上面执行.

        上面表达的意思是,子任务的后续任务跟子任务使用同一个线程.

3,任务调度器

           TaskScheduler.Default:使用线程池

          TaskScheduler.FromCurrentSynchronizationContext 获得一个同步的上下文调度器的使用,可以用来在Form程序中方便的

在异步线程中更新UI界面.否则需要使用Invoke的方式:

4,微软实列代码地址https://docs.microsoft.com/zh-cn/samples/browse/?redirectedfrom=MSDN-samples

5,https://docs.microsoft.com/en-us/previous-versions/msp-n-p/ff963552(v=pandp.10)

使用Parallel.For进行循环任务

      Parallel.ForEach 来进行迭代任务

      Parallel.Invoke进行多个方法执行.

Parallel方法都接受一个ParallelOption参数:

 public class ParallelOptions
    {
        public ParallelOptions() { }
        public CancellationToken CancellationToken { get; set; }
        public Int32 MaxDegreeOfParallelism { get; set; }//最大线程数,默认=-1,为cpu的数量

        public TaskScheduler TaskScheduler { get; set; }
    }

另外其还支持3个委托函数协助处理

 public static Int64 DirectoryBytes(string path, string searchPattern, SearchOption searchOption)
        {
            var files = Directory.EnumerateFiles(path, searchPattern, searchOption);//枚举所有的文件.
            Int64 mastertotals = 0;//累计全部bytes

            ParallelLoopResult result = Parallel.ForEach<String, Int64>(
                files,//tsource---需要处理的迭代对象.
                () =>0,//Tlocal---每个初始化值,传递给body.

                (file, loopState, taskLocalTotal) =>//处理函数,file是tsource的一个,loopstate是循环控制对象,taskLocakTotal是第一个
                //函数传递下来TLocal的初始值.用于给body使用.
                {
                    Int64 fileLength = 0;
                    FileStream fs = null;
                    try
                    {
                        fs = File.OpenRead(file);
                        fileLength = fs.Length;
                    }
                    catch (IOException) { }
                    finally
                    {
                        if (fs != null) fs.Dispose();

                    }
                    return taskLocalTotal + fileLength;
                },
                taskLocalTotal =>//这个参数是body函数的返回值,传递给Finally函数.Initial->Body->Finally.
                {
                    Interlocked.Add(ref mastertotals, taskLocalTotal);//安全的进行数据操作.
                }

                );
            return mastertotals;//返回值.
        }

  1,该函数的原型:

ParallelLoopResult ForEach<TSource,TLocal> (

IEnumerable<TSource> source, Func<TLocal> localInit,

Func<TSource,System.Threading.Tasks.ParallelLoopState,long,TLocal,TLocal> body,

Action<TLocal> localFinally);

2,ParallelLoopResult

IsCompleted
获取该循环是否已运行完成(即,该循环的所有迭代均已执行,并且该循环没有收到提前结束的请求)。
LowestBreakIteration
获取从中调用 Break() 的最低迭代的索引。

3,三个委托之间的关系:

           Func<TLocal>:用于初始化一个本地对象.

          Func<TSource,System.Threading.Tasks.ParallelLoopState,long,TLocal,TLocal> body,

          用于处理对象,

                 Tsource:处理源

                 ParallelLoopState:状态控制字

                           属性:IsExceptional:是否发生异常

                                  IsStopped : 是否调用Stop方法//会触发ShouldExit

                                 LowestBreakIteration:最低调用break的迭代

                                 ShouldExitCurrentIteration:

                                             在调用了break,stop或者异常,或者ParallelOption中的CancellationToken也会为true

                              stop();立即停止处理项

                              break();在处理完当前项后,尽快停止处理项.(保证处理完当前项)但是不保证该项是最后处理的项.所以,LowestBreakIteration保存了最低处理的项.

    4,可通过检查结果来了解:

                 如果complete=true ,则表明完成

                       如果LowestBreakIteration!=null则表明在某项调用了break

                       =null,则表明调用了stop方法.如果抛出异常,应该捕捉AggregateException来得体的恢复.

posted @ 2020-03-11 21:53  frogkiller  阅读(169)  评论(0编辑  收藏  举报