【问题标题】:Future / Completer behavior in dart not running asynchronously飞镖中的未来/完成者行为没有异步运行
【发布时间】:2016-12-11 07:37:49
【问题描述】:

我只是想了解 Futures 的行为。这是一个示例代码:

import'dart:async';

main() {

  Future short = shortWait();
  Future medium = mediumWait();
  Future long = longWait();
  long.then((String e)=>print(e));
  medium.then((String e)=> print(e));
  short.then((String e)=> print(e));
  }

  Future<String> longWait() {
  Completer c = new Completer<String>();
  for (int i=0; i<100000000; i++);   // creating long latency
  c.complete("long");
  return c.future;
  }
  Future<String> mediumWait() {
    Completer c = new Completer<String>();
    for (int i=0; i<10000; i++);    // creating medium length latency
    c.complete("medium");
    return c.future;
  }
  Future<String> shortWait() {
    Completer c = new Completer<String>();
    c.complete("short");    // no latency
    return c.future;
  }


// short  
// medium
// long

我注意到了一些事情。首先,代码似乎是同步的,而延迟最长的函数 longWait() 是阻塞的。直到所有内容都可用时才会显示输出,然后一次显示所有内容。我认为它应该首先显示任何可用的内容,然后在 Futures 完成时显示。

其次,显示顺序似乎反映了 Future short/medium/long = shortWait/mediumWait/longWait() 的显示顺序。即更改这些行的顺序,输出的顺序也会相应更改。每种方法的延迟时间有多长并不重要,也不会影响 short/medium/long.then((e) => print(e)) 的显示顺序。

我希望代码 1) 在数据可用时显示输出,以及 2) 输出顺序应该反映函数的延迟。除了理解 Futures 的基本概念之外,我实际上并没有尝试做任何事情。

【问题讨论】:

    标签: dart future


    【解决方案1】:

    请记住,Dart 中的 异步 并不意味着 并行

    您在示例中所做的实质是将五个任务放在一个队列中:

    1. 数到100000000
    2. 打印“长”
    3. 数到10000
    4. 打印“中等”
    5. 打印“短”

    所以他们按那个顺序执行。

    在 Dart 中,异步意味着代码在等待某事发生时不必阻塞。这通常是核心库提供的功能,例如从文件中获取数据,或通过网络进行交互——由操作系统或浏览器执行的任务。

    一种思考方式是,Dart 程序可以与操作系统或浏览器执行的操作“并行”执行,但不能与自身执行。

    Dart 还可以在等待计时器触发的情况下“并行”执行代码。例如:

    import 'dart:async';
    
    main() {
    
       // Long latency
      (new Future.delayed(new Duration(seconds: 5)).then((_) => print('long')));
    
      // Medium latency
      (new Future.delayed(new Duration(seconds: 2)).then((_) => print('medium')));
    
      // Short latency
      (new Future.delayed(new Duration(seconds: 1)).then((_) => print('short')));
    
      print('go');
    }
    

    打印:

    go
    short
    medium
    long
    

    【讨论】:

    • 只是补充一点,为了在 Dart 中并行处理,有Isolates 和方便的IsolateChannel 用于双向通信。
    • 谢谢。这很有帮助。我添加的延迟只是代表一些非常复杂的计算。时间延迟并不是一回事,我相信你会同意的。考虑到这一点,你是说没有简单的方法可以让这些函数并行工作,而不使用 Isolates,而只使用 Futures?
    • @rchkm 你可以设置0秒的延迟,然后在里面进行复杂的计算。
    • @rchkm 是的并发/并行函数仅使用隔离。 Dart 是单线程的,这是 IMO 的好东西。原因是 1) 使用共享内存进行并行编程 ala Java 被证明容易出错 2) 转换为 JS,它也是单线程的。一些更有用的链接:dartlang.org/tutorials/language/futureswebdev.dartlang.org/articles/performance/event-loop
    • @rchkm 正确在 Dart 中进行并行处理的唯一方法是使用 Isolate。
    【解决方案2】:
    Future<String> longWait() {
      Completer c = new Completer<String>();
      for (int i = 0; i < 100000000; i++); // creating long latency
      c.complete("long");
      return c.future;
    }
    

    这不是异步做事。只有在 for 循环完成后,您才会返回未来。这使得这个函数是同步的。

    要使其异步,请尝试以下操作:

    Future<String> longWait() {
      Completer c = new Completer<String>();
    
      new Future.delayed(new Duration(seconds: 4), () {
        c.complete('long');
      });
    
      return c.future;
    }
    
    Future<String> mediumWait() {
      Completer c = new Completer<String>();
    
      new Future.delayed(new Duration(seconds: 2), () {
        c.complete('medium');
      });
    
      return c.future;
    }
    
    Future<String> shortWait() {
      Completer c = new Completer<String>();
    
      new Future.delayed(new Duration(seconds: 0), () {
        c.complete('short');
      });
    
      return c.future;
    }
    

    理想情况下,您可以完全避免使用Completer,因为Future.delayed 返回一个未来。

    Future<String> longWait() {
      return new Future.delayed(new Duration(seconds: 10), ()=>'long');
    }
    Future<String> mediumWait() {
      return new Future.delayed(new Duration(seconds: 5), ()=>'medium');
    }
    Future<String> shortWait() {
      return new Future.delayed(new Duration(seconds: 0), ()=>'short');
    }
    

    【讨论】:

    • 谢谢。整个代码仍然暂停,等待一切,然后在完成时运行。打印的顺序似乎仍然与我在 main() 中创建 Future 对象的顺序有关。如果 Future 只在循环之后返回,shortWait() 函数不应该先返回一个值,然后是 mediumWait(),然后是 longWait()?当我使用 new Future.delayed(new Duration(seconds: 10)) 时,我认为系统实际上并没有等待 10 秒。再次感谢。我把它放在飞镖板上。 (dartpad.dartlang.org/3f22a756c9f4c98d55f8dbb2eb062314)
    • 当您使用时间延迟时,它会返回一个 Future,因此您不必使用 Completer。看到这个dartpad.dartlang.org/e373c3f73e7b8d2e5f11a8b0ee290195
    • @rchkm 我之前在答案中写的代码是错误的。我已经用正确的代码更新了答案。
    猜你喜欢
    • 1970-01-01
    • 2021-09-05
    • 1970-01-01
    • 2021-11-28
    • 1970-01-01
    • 2019-05-20
    • 1970-01-01
    • 1970-01-01
    • 2019-07-05
    相关资源
    最近更新 更多