【问题标题】:Return synchronously called Futures asynchronously in order of execution in queue in Dart在 Dart 的队列中按执行顺序异步返回同步调用的 Futures
【发布时间】:2021-11-29 02:01:57
【问题描述】:
void main() async {
  Future<void> asyncFunction(time, value) async {
    return await Future.delayed(Duration(seconds: time), () => print(value));
  }

  print('1');
  asyncFunction(2, "A");
  asyncFunction(1, "B");
  asyncFunction(0, "C");
  print('2');
}

根据上面的代码,我正在尝试将代码打印为:

1
2
A
B
C

我想同步执行所有函数并将 asyncFunctions (Futures) 发送到一种队列,然后按照接收顺序执行这些函数。每个函数都必须等待前一个函数完成它的 Future 才能执行。

我一直在尝试使用流,但没有做好。

【问题讨论】:

    标签: dart asynchronous stream queue future


    【解决方案1】:

    这行得通吗?

    void main() async {
      Future<void> asyncFunction(time, value) async {
        return await Future.delayed(Duration(seconds: time), () => print(value));
      }
    
      print('1');
      print('2');
      await asyncFunction(2, "A");
      await asyncFunction(1, "B");
      await asyncFunction(0, "C");
    }
    

    【讨论】:

    • 不,我想同步调用这些函数。它们应该被放置在一种队列中,以便在前一个完成后每个都执行
    • 但是这样一来,每一个都会在前一个完成后执行。
    • 是的,但是'2'最后打印,因为它必须等待
    • 哦哦,打印'1'后立即打印'2'会有问题吗?
    • 我希望它打印 1、2、A、B、C,这些字母被延迟但时间不同,因此它们每个都必须等待前一个完成。
    【解决方案2】:

    好的,我设法想出了一些补充:

    import 'dart:async';
    import 'dart:collection';
    import 'dart:math';
    
    var streamController = StreamController<String>();
    Queue queue = Queue();
    bool busy = false;
    
    Future<void> asyncFunction(value) async {
      await Future.delayed(Duration(seconds: Random().nextInt(4)));
      return print(value);
    }
    
    void main() async {
      streamController.stream.listen((letter) async {
        queue.add(letter);
        if (!busy) {
          busy = true;
          while (busy) {
            await asyncFunction(queue.first);
            queue.removeFirst();
            if (queue.isEmpty) {
              busy = false;
            }
          }
        }
      });
    
      print("1");
      streamController.add("A");
      streamController.add("B");
      streamController.add("C");
      streamController.add("D");
      print("2");
      streamController.add("E");
      streamController.add("F");
      streamController.add("G");
      streamController.add("H");
      print("3");
      print("-");
    }
    

    给出期望的结果:

    1
    2
    3
    -
    A
    B
    C
    D
    E
    F
    G
    H
    

    【讨论】:

      【解决方案3】:

      没有办法让Future.delayed(2, ...)Future.delayed(1, ...) 之前完成。时间不是这样运作的。相反,您可以做的是依赖返回值而不是副作用,然后您可以构建 Futures 的 List 并使用 Future.wait 收集结果并按原始顺序打印它们:

      void main() async {
        Future<dynamic> asyncFunction(time, value) async {
          await Future.delayed(Duration(seconds: time));
          return value;
        }
      
        var futures = <Future<dynamic>>[];
        
        print('1');
        futures.add(asyncFunction(2, "A"));
        futures.add(asyncFunction(1, "B"));
        futures.add(asyncFunction(0, "C"));
        print('2');
        
        var results = await Future.wait(futures);
        for (var result in results) {
          print(result);
        }
      }
      

      上述方法的好处是允许多个异步操作潜在地并行运行。

      或者,您可以延迟构造 Future.delayed(...) 对象,以便在前一个完成之前不会创建每个对象:

      void main() async {
        Future<void> asyncFunction(time, value) async {
          await Future.delayed(Duration(seconds: time), () => print(value));
        }
      
        var queue = <Future<void> Function()>[];
        
        print('1');
        queue.add(() => asyncFunction(2, "A"));
        queue.add(() => asyncFunction(1, "B"));
        queue.add(() => asyncFunction(0, "C"));
        print('2');
        
        for (var thunk in queue) {
          await thunk();
        }
      }
      

      【讨论】:

        【解决方案4】:

        如果您想要一个异步任务队列,其中添加的每个新任务都会延迟到前一个任务完成,您可以自己编写一个。

        class AsyncQueue<T> {
          Future<T?> _current = Future.value(null);
          Future<T> add(FutureOr<T> Function() task) {
            FutureOr<T> wrapper(void _) => task();
            return _current = _current.then(wrapper, onError: wrapper);
          }
        }
        

        你可以用作:

        Future<void> asyncFunction(time, value) async {
          await Future.delayed(Duration(seconds: time), () => print(value));
        }
        ...
          var queue = AsyncQueue<void>();
          print("1");
          var f1 = queue.add(() => asyncFunction(2, "A"));
          var f2 = queue.add(() => asyncFunction(1, "B"));
          var f3 = queue.add(() => asyncFunction(0, "C"));
          print("2");
          await f3;
        

        【讨论】:

          猜你喜欢
          • 2013-01-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-07-16
          • 1970-01-01
          相关资源
          最近更新 更多