zoukankan      html  css  js  c++  java
  • .Net 异步随手记(二)

    Task.ContinueWith

    这货,和 await 一样有“陷阱”。^^,因为写 ContinueWith 不能直观如人的“过程性”思维,写在 ContinueWith 括号里的部分不一定只在发起 ContinueWith 的任务完成后完成,比如这样:

     1 namespace TaskConsole
     2 {
     3     class Program
     4     {
     5         static void Main(string[] args)
     6         {
     7             while (true)
     8             {
     9                 var enter = Console.ReadLine();
    10 
    11                 if (enter.ToLower() == "continue") { Entry(); }
    12                 else { break; }
    13             }
    14         }
    15 
    16 
    17         async static void DoWork(string workerName)
    18         {
    19             await Task.Delay(1000);
    20             Console.WriteLine("{0} is working @ Thread Id {1}", workerName, System.Threading.Thread.CurrentThread.ManagedThreadId);
    21         }
    22 
    23         async static void DoClean(string cleaner)
    24         {
    25             await Task.Delay(1000);
    26             Console.WriteLine("{0} is cleaning @ Task Id {1}", cleaner, Task.CurrentId);
    27         }
    28 
    29         async static Task Entry()
    30         {
    31             var task = Task.Factory.StartNew(() => DoWork("工作者1")).
    32                         ContinueWith(backer => DoClean("清理者1")).
    33                         ContinueWith(backer => DoClean("清理者2")).
    34                         ContinueWith(backer => DoClean("清理者3"));
    35         }
    36     }
    37 }

    运行一下试试?如果过程中没有 await Task.Delay 参与,看起来基本是按顺序的,但是这句一加上就立马露陷了,看

    那如何让 ContinueWith 按我们的心思走呢?对了,还有其它参数可以用,让我们随便试试

    1 var task = Task.Factory.StartNew(() => DoWork("工作者1")).
    2                         ContinueWith(backer => DoClean("清理者1"), TaskContinuationOptions.NotOnRanToCompletion).
    3                         ContinueWith(backer => DoClean("清理者2"), TaskContinuationOptions.OnlyOnRanToCompletion).
    4                         ContinueWith(backer => DoClean("清理者3"), TaskContinuationOptions.OnlyOnRanToCompletion);

    运行一下,咦,发生了什么?

    为什么清理者都不工作了?问题出在参数 【TaskContinuationOptions.NotOnRanToCompletion】,它起了作用,它告诉第一个清理者“当工作者任务不是正常完成时你才能启动”,所以清理者1就没有机会启动,它没有机会启动,后面的清理者2、清理者3自然都没有办法启动。到这里只知道 ContinueWith 还有参数可以利用,但是没有达到我们的目的,继续!先把两个 void 方法改造一下

     1 async static Task DoWork(string workerName)
     2 {
     3     await Task.Delay(1000);
     4     Console.WriteLine("{0} is working @ Thread Id {1}", workerName, System.Threading.Thread.CurrentThread.ManagedThreadId);
     5 }
     6 
     7 async static Task DoClean(string cleaner)
     8 {
     9     await Task.Delay(1000);
    10     Console.WriteLine("{0} is cleaning @ Task Id {1}", cleaner, Task.CurrentId);
    11 }

    变成了 Task 的方法,就有了控制的前提条件,接下来改造一下 ContinueWith 的流程

    1 {
    2     var taskWorker = Task.Factory.StartNew(() => DoWork("工作者1"));
    3     await taskWorker.Result;
    4     var c1 = await taskWorker.ContinueWith(backer => DoClean("清理者1"), TaskContinuationOptions.OnlyOnRanToCompletion);
    5     var c2 = await c1.ContinueWith(backer => DoClean("清理者2"), TaskContinuationOptions.OnlyOnRanToCompletion);
    6     var c3 = await c2.ContinueWith(backer => DoClean("清理者3"), TaskContinuationOptions.OnlyOnRanToCompletion);
    7 }

    把原来写在一起的一堆 ContinueWith 分开,让它们各自“拥有身份”,并且按顺序去继承上一个 Task,只有当指定的 Task 执行完成到 RanToCompletion 的状态时自身才被启用,并且 await 的使用保证了 taskWorker 运行完成 C1 才会执行,C1 运行完 C2 才会执行,C2 运行完 C3 才会执行。到此,似乎实现了我们的要求。

  • 相关阅读:
    Mybatis核心
    正则表达式(二)Java中正则表达式的使用
    Elasticsearch(ES)分词器的那些事儿
    并发编程之:JUC并发控制工具
    scrollTo()和scrollBy()的区别
    SpringBoot 的@Value注解太强大了,用了都说爽!
    SQL 查询并不是从 SELECT 开始的
    jsoup 教程
    爬虫
    case when以及集合聚合函数的用法
  • 原文地址:https://www.cnblogs.com/cinlap/p/5762792.html
Copyright © 2011-2022 走看看