zoukankan      html  css  js  c++  java
  • 任务

      任务表示某个工作单元。这个工作单元可以在单独的线程中运行,也可以同步方式启动一个任务,使主线程等待。任务可以在完成后定义一个连续工作,同时也可以有子任务(但取消父任务后,子任务也会被取消)。

    1、启动任务

      使用TaskFactory类或Task类的构造方法和Start()方法。启动任务时,会创建一个Task类的实例,利用Action或者Action<object>委托,可以指定应该运行的代码。创建一个方法作为后面线程调用的代码:

    static void TaskMethod(object title)
    {
        lock (taskMethodLock)
        {
            Console.WriteLine(title);
            Console.WriteLine("Task id: {0}, thread: {1}",
              Task.CurrentId == null ? "no task" : Task.CurrentId.ToString(),
              Thread.CurrentThread.ManagedThreadId);
            Console.WriteLine("is pooled thread: {0}", Thread.CurrentThread.IsThreadPoolThread);
            Console.WriteLine("is background thread: {0}", Thread.CurrentThread.IsBackground);
            Console.WriteLine();
        }
    }

    1.1、使用线程池的任务

      创建任务有四种方式: 

    static void TasksUsingThreadPool()
    {
        TaskFactory tf = new TaskFactory();
        Task t1 = tf.StartNew(TaskMethod, "using a task factory");
    
        Task t2 = Task.Factory.StartNew(TaskMethod, "factory via a task");
    
        Task t3 = new Task(TaskMethod, "using a task constructor and Start");
        t3.Start();
    
        Task t4 = Task.Run(() => TaskMethod("using the Run method"));
    }
    

      使用Task构造函数和TaskFactory的StartNew方法时,可以传递TaskCreationOptions的枚举值。它可以改变任务的行为。

    1.2、同步任务

      任务可以同步运行,以相同的线程作为主调线程。使用Task的RunSynchronously方法:

    private static void RunSynchronousTask()
    {
        TaskMethod("just the main thread");
        var t1 = new Task(TaskMethod, "run sync");
        t1.RunSynchronously();
    }
    

      首先TaskMethod方法在主线程调用,然后在新创建的Task上调用。运行代码,从输出可以看出,主线程是一个前台线程。没有任务ID,也不是线程池的线程。调用RunSyncronously方法时,会使用相同的线程作为主调线程,但是如果以前没有创建任务,就会创建一个新任务。

    1.3、使用单独线程的任务

      如果任务需要长时间运行,那么使用TaskCreationOptions.LongRunning告诉任务调度器创建一个新的线程,而不是使用线程池中的线程。新线程将不受线程池管理。如果线程来自于线程池,任务调度器可以决定等待已经运行的任务完成,然后使用这个线程,而不是在线程中创建一个新的线程。对于长时间运行的线程,任务调度器会立即知道不能等待它们完成。

    2、Futrue——任务的结果

      任务结束时,可以把一些有用的信息写入共享对象中,但共享对象必须是线程安全的。另一种方法是使用返回某个结果的任务:

    static void ResultsFromTasks()
    {
        //TResult是后面Func的返回值,第二个参数是Func的传入参数
        Task<Tuple<int, int>> t1 = new Task<Tuple<int, int>>(TaskWithResult, Tuple.Create<int, int>(8, 3));
        t1.Start();
        Console.WriteLine(t1.Result);//在此等待任务的完成,返回结果
                                     //t1.Wait();
        Console.WriteLine("result from task: {0} {1}", t1.Result.Item1, t1.Result.Item2);
    }
    
    static Tuple<int, int> TaskWithResult(object division)
    {
        Tuple<int, int> div = (Tuple<int, int>)division;
        int result = div.Item1 / div.Item2;
        int reminder = div.Item1 % div.Item2;
        Console.WriteLine("task creates a result...");
    
        return Tuple.Create<int, int>(result, reminder);
    }

    3、连续任务

      可以指定在任务完成后,应该开始运行的另一个特定任务。如:一个任务失败后,那么任务的后续工作就是清理工作。任务处理程序不带参数,或者带一个object类型的参数,连续处理程序有一个Task类型的参数,可以访问起始任务的相关信息。

     static void ContinuationTask()
     {
         Task t1 = new Task(DoOnFirst);
         //连续任务通过在任务上调用ContinueWith方法定义,也可以使用TaskFactory类。
         Task t2 = t1.ContinueWith(DoOnSecond);//调用DoOnSecond方法的新任务在任务t1结束后立即启动。
         Task t3 = t1.ContinueWith(DoOnSecond);//在一个任务结束时,可以启动多个任务
         Task t4 = t2.ContinueWith(DoOnSecond);//连续任务也可以另一个连续任务
         //无论前一个任务是如何结束的,前面的连续任务都会在前一个任务结束时启动
         //使用TaskContinuationOptions的枚举值,可以指定连续任务启动的前提条件(前一个任务的状态)
         Task t5 = t1.ContinueWith(DoOnError, TaskContinuationOptions.OnlyOnFaulted);
         t1.Start();
         Thread.Sleep(5000);
     }
    
     static void DoOnFirst()
     {
         Console.WriteLine("doing some task {0}", Task.CurrentId);
         Thread.Sleep(3000);
     }
    
     static void DoOnSecond(Task t)
     {
         Console.WriteLine("task {0} finished", t.Id);
         Console.WriteLine("this task id {0}", Task.CurrentId);
         Console.WriteLine("do some cleanup");
         Thread.Sleep(3000);
     }
    
     static void DoOnError(Task t)
     {
         Console.WriteLine("task {0} had an error!", t.Id);
         Console.WriteLine("my id {0}", Task.CurrentId);
         Console.WriteLine("do some cleanup");
     }

    4、任务层次结构

      利用任务的连续性,可以在一个任务结束后启动另一个任务。任务也可以构成一个层次结构,一个任务启动一个新任务时,就启动了一个父/子层次结构。

     static void ParentAndChild()
     {
         Task parent = new Task(ParentTask);
         parent.Start();
         Thread.Sleep(2000);
         Console.WriteLine(parent.Status);
         Thread.Sleep(4000);
         Console.WriteLine(parent.Status);
     }
     static void ParentTask()
     {
         Console.WriteLine("task id {0}", Task.CurrentId);
         var child = new Task(ChildTask);
         child.Start();
         Thread.Sleep(1000);
         Console.WriteLine("parent started child");
     }
     static void ChildTask()
     {
         Console.WriteLine("child");
         Thread.Sleep(5000);
         Console.WriteLine("child finished");
     }

      父任务在子任务之前结束,则父任务状态为WaitingForChildrenToComplete;所有的子任务也结束时,父任务的状态为RanToCompletion。取消父任务,也会取消子任务。

    //:启动父/子关系结构任务的另一种方法
    static void ParentAndChild()
    {
        TaskFactory factory = new TaskFactory();
        Task parent = factory.StartNew(() =>
           {
               Console.WriteLine("parent task {0}", Task.CurrentId);
    
               Task child = factory.StartNew(() =>
               {
                   Console.WriteLine("child task {0}", Task.CurrentId);
                   Thread.Sleep(2000);
                   Console.WriteLine("finished child");
               }, TaskCreationOptions.AttachedToParent);
    
               Console.WriteLine("finished parent");
           });
        parent.Wait();
    }

    5、任务的取消

      

    static void CancelTask()
    {
        var cts = new CancellationTokenSource();//也可以使用Task.Factory.CancellationToken(如果仅需要一个取消标记)
        cts.Token.Register(() => Console.WriteLine("*** task cancelled"));//在发生取消标记时调用。
        cts.CancelAfter(500);            //500ms后取消任务
        Task t1 = Task.Run(() =>
          {
              Console.WriteLine("in task");
              for (int i = 0; i < 20; i++)
              {
                  Thread.Sleep(100);
                  CancellationToken token = cts.Token;
                  if (token.IsCancellationRequested)
                  {
                      Console.WriteLine("cancelling was requested, cancelling from within the task");
                      token.ThrowIfCancellationRequested();//注意:运行调试程序会在此处报异常,运行exe会在下面捕捉到异常
                      break;
                  }
                  Console.WriteLine("in loop");
              }
              Console.WriteLine("task finished without cancellation");
          }, cts.Token);
    
        try
        {
            t1.Wait();
        }
        catch (AggregateException ex)
        {
            Console.WriteLine("exception: {0}, {1}", ex.GetType().Name, ex.Message);
            foreach (var innerException in ex.InnerExceptions)
            {
                Console.WriteLine("inner excepion: {0}, {1}", ex.InnerException.GetType().Name, ex.InnerException.Message);
            }
        }
    }
  • 相关阅读:
    nodejs
    flask中flash(闪现)的使用
    flask中logger日志的使用
    flask中session的使用
    flask开启调试模式
    flask中静态文件的引入
    flask中模板引入
    python web开发屠龙刀flask
    python操作excel基础1-环境搭建
    php算法-dijkstra
  • 原文地址:https://www.cnblogs.com/pilgrim/p/9471268.html
Copyright © 2011-2022 走看看