我正在实现一个令牌生成器。它解析文档,在一组可能的定界符上对它进行标记,然后为我提供1、2和3字标记的组合。 我能够实现自己的目标,但是只能通过一种特定的方式进行:
Stream<String> contentStr = file.openRead().transform(utf8.decoder);
Stream<String> tokens = contentStr.transform(charSplitter).transform(tokenizer).asBroadcastStream();
var twoWordTokens = tokens.transform(sliding(2));
var threeWordTokens = tokens.transform(sliding(3));
StreamController<String> merger = StreamController();
tokens.forEach((token) => merger.add(token));
threeWordTokens.forEach((token) => merger.add(token));
twoWordTokens.forEach((token) => merger.add(token));
merger.stream.forEach(print);
如您所见,我将执行以下操作:
StreamConsumer
(准确地说是StreamController
),并将每个事件从3个流中抽取到该流的使用者。它可以工作,但是我不喜欢通过StreamConsumer.add
方法添加源流中的每个元素。我想改用StreamController.addStream
,但是那不起作用。
以下代码给我一个Bad state: Cannot add event while adding a stream
错误,我明白原因:
StreamController<String> merger = StreamController();
merger.addStream(tokens);
merger.addStream(twoWordTokens);
merger.addStream(threeWordTokens);
merger.stream.forEach(print);
这是StreamController.addStream
中的API documentation。
因此,我需要等待每个addStream
返回将来的完成情况:
StreamController<String> merger = StreamController();
await merger.addStream(tokens);
await merger.addStream(twoWordTokens);
await merger.addStream(threeWordTokens);
await merger.stream.forEach(print);
但是在这种情况下,控制台上什么也没打印。
如果我这样做:
StreamController<String> merger = StreamController();
merger.stream.forEach(print);
await merger.addStream(tokens);
await merger.addStream(twoWordTokens);
await merger.addStream(threeWordTokens);
然后仅打印1字令牌,即原始广播流的元素。派生流的元素不是。
我有点理解为什么会这样,因为我的所有流都是从原始广播流派生的。
是否有更好的方法来实现这样的管道?
可能我的问题可以用流复制/分叉来重新表示,但是我看不到在Dart中克隆流的方法。如果您可以提供建议-请这样做。
答案 0 :(得分:1)
我希望在某个时候允许并发addStream
,但是在那之前,您需要独立处理事件:
var allAdds = [
tokens.forEach(merger.add),
twoWordTokens.forEach(merger.add),
threeWordTokens.forEach(merger.add)];
Future.wait(allAdds).then((_) { merger.close(); });
merger.stream.forEach(print);
那是如果您想自己控制一切。您还可以使用package:async
中的StreamGroup
类。它收集大量流并将其事件作为单个流发出。
这假定您没有错误事件。