【问题标题】:Dart: Do I have to cancel Stream subscriptions and close StreamSinks?Dart:我必须取消 Stream 订阅并关闭 StreamSinks 吗?
【发布时间】:2018-09-27 11:59:02
【问题描述】:

我知道当我不想再接收任何事件时,我必须取消 Stream 订阅。 即使在收到“完成”事件后,我也必须这样做吗?还是会出现内存泄漏?

传递给另一个 Stream 的 addStream 的 Stream 会发生什么情况?他们会自动取消吗?

StreamSink 方面的相同问题如果流已经完成,我是否必须关闭它们?

【问题讨论】:

    标签: stream dart


    【解决方案1】:

    简短回答:不,但你应该StreamSubscriptionStreamSink 的合同中没有任何内容要求关闭资源,但是如果您不关闭它们,某些用例可能会导致内存泄漏,即使在某些情况下这样做也是如此可能会令人困惑。这些类的部分混淆在于它们被重载,并且处理两个相当不同的用例:

    1. 资源流(如文件 I/O、网络访问)
    2. 事件流(如点击处理程序)

    让我们一次一个地解决这些问题,首先,StreamSubscription

    StreamSubscription

    当您将listen 发送到Stream 时,您会收到StreamSubscription。一般来说,当您完成收听Stream 时,无论出于何种原因,您都应该关闭订阅。如果选择不这样做,并非所有流都会泄漏内存,但有些流会泄漏 - 例如,如果您正在从文件中读取输入,则不关闭流意味着文件的句柄可能保持打开状态。

    所以,虽然不是严格要求,但我会总是在访问完流时cancel

    StreamSink

    StreamSink 最常见的实现是StreamController,它是创建Stream 的编程接口。通常,当您的流完成(即所有数据已发出)时,您应该关闭控制器。

    这里有点令人困惑。让我们看看这两种情况:

    文件 I/O

    假设您正在创建一个 API 来逐行异步读取文件:

    Stream<String> readLines(String path);
    

    要实现这一点,您可以使用StreamController

    Stream<String> readLines(String path) {
      SomeFileResource someResource;
      StreamController<String> controller;
      controller = new StreamController<String>(
        onListen: () {
          someResource = new SomeFileResource(path);
          // TODO: Implement adding to the controller.
        },
      );
      return controller.stream;
    }
    

    在这种情况下,当读完最后一行时关闭controller 会很有意义。这会向用户发出信号(done 事件),表明文件已被读取,并且是有意义的(例如,您可以在那时关闭 File 资源)。

    活动

    假设您正在创建一个 API 来收听 HackerNews 上的新闻文章:

    Stream<String> readHackerNews();
    

    在这里,关闭底层接收器/控制器的意义不大。 HackerNews 会停止吗?像这样的事件流(或 UI 程序中的 click 处理程序)传统上不会在没有用户访问的情况下“停止”(即取消 StreamSubscription)。

    可以在完成后关闭控制器,但这不是必需的。


    希望这是有道理的,可以帮助你!

    【讨论】:

    • 谢谢!只有您的简短回答与您以后的阐述不一致。但它让我现在有了更好的理解。非常感谢
    • 我认为答案确实是“是的,你应该”,而“不,你没有必须”在技术上是正确的(如详细说明由剩余的文本)。也就是说,在某些情况下您不需要这样做,但总是自己清理会更容易(并将例外情况留给少数情况下不太容易并且你知道你不需要需要)。当您在订阅中看到 listencancel 匹配时,比查看代码却看不到任何对象生命周期的迹象更容易理解代码。
    • 我认为 Dart 不允许重载。你这是什么意思?
    【解决方案2】:

    我发现如果我有这样的代码:

    Stream<String> readHackerNews(String path) {  
      StreamController<String> controller = StreamController<String>();
    
      ......
    
      return controller.stream;
    }
    

    我看到一条警告消息“关闭 'dart.core.Sink' 的实例”。在 Visual Studio 代码中。 为了解决这个警告,我添加了

    controller.close()
    

    到 OnCancel 事件的事件处理程序,见下文:

    Stream<String> readHackerNews(String path) {  
      StreamController<String> controller = StreamController<String>();
    
      //TODO: your code here
    
      controller.onCancel = () {
        controller.close();
      };
    
      return controller.stream;
    }
    

    希望这会有所帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-09
      • 2018-09-26
      • 2018-05-08
      • 2011-07-02
      • 2021-07-19
      • 2019-03-06
      相关资源
      最近更新 更多