【问题标题】:Why doesn't Keep.None affect the Akka stream execution result?为什么 Keep.None 不影响 Akka 流执行结果?
【发布时间】:2017-05-17 14:52:16
【问题描述】:

我有一个简单的 Akka Streams 测试代码(用 F# 编写,但 Scala 版本不匹配):

    var source = Source.From(Enumerable.Range(1, 3));
    var flow = Flow.FromFunction(new Func<int, string>(x => (x * 2).ToString()));
    var sink = Sink.ForEach<string>(output.Add);
    var runnable = source.Via(flow).To(sink);

由于 Via 辅助方法只是 ViaMaterialized(flow, Keep.Left) 的快捷方式,我可以这样重写代码:

var source = Source.From(Enumerable.Range(1, 3));
var flow = Flow.FromFunction(new Func<int, string>(x => (x * 2).ToString()));
var sink = Sink.ForEach<string>(output.Add);
var runnable = source.ViaMaterialized(flow, Keep.Left).To(sink);

Keep 属性(Left、Right、Both 或 None)告诉流实现器应该保留流操作指定侧的值。但我注意到,如果我将 Keep.Left 更改为 Keep.Right、Keep.Both 或事件 Keep.None,这不会改变执行结果中的任何内容:接收器将始终根据流转换函数接收输出。

我认为在流图中为 Flow 阶段使用 non-None Keep 值对于确保将值发送到接收器是必要的。我一定误解了这个意思,所以我的问题是为什么即使双方都禁用了物化,流也能工作?您能否举例说明在 Left、Right、Both 和 None 之间更改 Keep 值会影响到达接收器的值?

【问题讨论】:

  • 这些代码 sn-ps 是 C#,而不是 F#。

标签: scala f# akka-stream


【解决方案1】:

您混淆了流被物化的事实和它具有物化值的事实。

流(或更一般地,图)是流的蓝图。当您在可运行图上使用 run() 方法时,将使用此蓝图实现流。此流执行任何预期的操作,而不考虑物化值。

什么是物化价值?当您使用方法run() 时,将返回一个值。这就是您的流的物化值。大多数时候(对于简单的内置阶段),物化值并不重要(在 scala 中称为 NotUsed,我不了解 .NET)。一个重要的例子是Sink.ignore,它被具体化为Future[Done]。它可以让您了解您已物化的特定流何时完全消耗其输入(或引发错误)。更一般地说,物化值会为您提供有关流中发生的情况的一些间接信息(很抱歉此陈述含糊不清,但手头的原则过于笼统,我无法更明确地说明)。

在构建图表时,您将具有不同物化值的不同部分放在一起。由于您的可运行图只能有一个,因此您需要以某种方式将它们组合起来。 Keep.{right, left, both, none} 是简单的函数,它们通过仅保留一个值,或两者兼而有之,或不保留这些值来组合这些值。但是,即使您决定不保留它们,这也不会改变这两个图都将被具体化以及生成的值这一事实。

【讨论】:

  • 谢谢。我确实混淆了不同的东西。现在很清楚了。
【解决方案2】:

Keep.* 函数不会影响具体化过程本身,只会影响您从中获得的结果。

更具体地说,在具体化时(即调用 run() 时),流的每个阶段(在您的示例中为源、流和接收器)都将始终实现 - 并且因此在幕后产生了一个物化的价值。您可以从它们的最后一个类型参数清楚地看到该值是什么。

为了方便用户,您很可能不会对所有这些都感兴趣,您可以相应地使用Keep.* 来选择要保留的内容。这直接反映在run()的返回类型上。

【讨论】:

  • 感谢您的解释。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-05-28
  • 2013-05-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多