【问题标题】:How do I get a dart Stream with uneven intervals?如何获得间隔不均匀的飞镖流?
【发布时间】:2021-10-01 05:18:50
【问题描述】:

我是 dart 和 Flutter 的新手,很想就我面临的算法问题获得一些建议。

我想将我的 Flutter 应用程序连接到蓝牙设备(该部分已完成,我已经连接)并以不均匀的间隔发送消息。我有一个列表中的消息,对于每个消息,我都知道我想在什么时间(毫秒)发送消息。

所以假设下面的消息是一字排开的:

  • start 0 毫秒
  • init_app 100 毫秒
  • user_pick_x 500 毫秒
  • user_start_x 500ms (将在user_pick_x 之后发送,应保证订单)
  • interrupt 3500 毫秒

我找到了创建流的文档,但它总是谈论单个间隔值。 https://dart.dev/articles/libraries/creating-streams.

想法:

  • 从技术上讲,我可以传入Duration 对象列表,并使用自定义生成器async* 以及消息字符串。
  • 或者,我可以将时间间隔设置为最低时间增量,并检查每个时间间隔是否应发送消息。在示例的情况下,每 100 毫秒。

如果能够暂停/取消流也很好。这是流本身可以做的事情。

【问题讨论】:

    标签: flutter dart dart-stream


    【解决方案1】:

    我认为最简单的方法是在指定的时间间隔发出这些消息。比如:

    Future<void> _wait(int milliseconds) async =>
      await Future<void>.delayed(Duration(milliseconds: milliseconds));
    
    Stream<String> generateMessages() async* {
      yield 'start';
      await _wait(100);
      yield 'init_all';
      await _wait(400);
      yield 'user_pick_x';
      yield 'user_start_x';
      await _wait(3000);
      yield 'interrupt';
    }
    
    void main() {
      generateMessages().listen((msg) {
        print('${DateTime.now()}: $msg');
      });
    }
    

    将打印:

    2021-07-25 10:21:21.429: start
    2021-07-25 10:21:21.531: init_all
    2021-07-25 10:21:21.934: user_pick_x
    2021-07-25 10:21:21.934: user_start_x
    2021-07-25 10:21:24.938: interrupt
    

    如果您想确保流的侦听器异步接收事件 - 因此不干扰等待毫秒,您可以显式使用默认情况下异步调用侦听器的 StreamController(确保导入 dart:async --- dart:io 仅用于sleep 的示例中,以表明即使在阻塞操作中它也会与等待并行运行):

    import 'dart:async';
    import 'dart:io';
    
    Future<void> _wait(int milliseconds) async {
      print('WAIT $milliseconds ms');
      await Future<void>.delayed(Duration(milliseconds: milliseconds));
    }
    
    Stream<String> generateMessages() {
      final controller = StreamController<String>(sync: false);
      controller.onListen = () async {
        controller.add('start');
        await _wait(100);
        controller.add('init_all');
        await _wait(400);
        controller.add('user_pick_x');
        controller.add('user_start_x');
        await _wait(3000);
        controller.add('interrupt');
      };
      return controller.stream;
    }
    
    void main() {
      generateMessages().listen((msg) {
        sleep(const Duration(milliseconds: 120));
        print('${DateTime.now()}: $msg');
      });
    }
    

    【讨论】:

    • 这很好用,谢谢!我唯一的疑问是时间是否会慢慢提前发送的预定时间。因此流的消息发布将花费几毫秒,导致所有后续的期货和消息也被延迟。这是真的吗,如果是的话,我可以解决这个问题吗?
    • @Robin 这取决于听众做什么。如果侦听器仅触发自己的异步调用,则延迟应该可以忽略不计。另一方面,如果监听器做了一些阻塞(如File().writeAsBytesSync(...))或一些繁重的操作,它可能会增加延迟。我添加了一个使用显式 StreamController 的示例,这将确保异步调用侦听器。尽管请注意,它本质上仍然是单线程的。因此,如果您的侦听器需要超过 100 毫秒的同步工作,那么 init_all 可能会在 100 毫秒后被调用。
    • 即。如果您在主隔离中进行 200 毫秒的重加密,则不会完成任何其他操作,即使使用异步 StreamControllerwait 也不会在 100 毫秒后完成 - 因为在隔离中总是只能有一个同步工作。如果是这种情况,你必须做长时间的阻塞工作,你可能会考虑产生一个单独的隔离。
    • 是的,看起来很完美!正如我所说,该应用程序是蓝牙设备。鉴于会有来回通信,单独的隔离听起来是个好主意。这将充当我设备的接口。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-08-03
    • 1970-01-01
    • 2022-01-15
    • 1970-01-01
    • 2018-10-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多