为什么Keep.None不影响Akka流执行结果?
Why doesn't Keep.None affect the Akka stream execution result?
我有一个简单的 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 or None) 告诉流实体化器应该保留流操作指定端的值。但我注意到,如果我将 Keep.Left 更改为 Keep.Right、Keep.Both 或事件 Keep.None,这不会改变执行结果中的任何内容:接收器将始终接收输出根据流量变换函数
我认为在流图中使用非 None 保持流阶段的值对于确保将值发送到接收器是必要的。我一定是误解了这个的意思,所以我的问题是为什么即使双方都禁用了物化,流仍然有效?您能否举例说明在左、右、两者之间更改保持值和 None 会影响到达接收器的值?
Keep.*
函数不会影响具体化过程本身,只会影响您从中得到的东西。
更具体地说,在实现时(即调用 run()
时),流的每个阶段(在您的示例中为源、流和汇)将 始终 被具体化 - 因此在引擎盖下产生具体化的价值。您可以从他们的最后一个类型参数中清楚地看到该值是什么。
为了方便用户,您很可能不会对所有这些都感兴趣,您可以相应地使用 Keep.*
到 select 什么 保留 大约。这直接体现在run()
的return类型上。
您混淆了流被具体化的事实和它具有具体化值的事实。
流(或更一般地说是图形)是流的蓝图。当您在可运行图上使用 run()
方法时,将使用此蓝图具体化一个流。这个流做任何它期望的事情,而不考虑物化值。
什么是物化值?当您使用 run()
方法时,会返回一个值。这就是您的流的物化价值。大多数时候(对于简单的内置阶段),物化值并不重要(它在 scala 中称为 NotUsed
,我不知道 .NET)。一个重要的例子是 Sink.ignore
被具体化为 Future[Done]
。它为您提供了具体化的特定流何时完全消耗其输入(或抛出错误)的句柄。更一般地说,物化值为您提供了一些关于您的流中发生的事情的间接信息(很抱歉这种说法含糊不清,但手头的原则太笼统了,我无法更明确)。
构建图表时,您将具有不同物化值的不同部分放在一起。由于您的可运行图只能有一个,因此您需要以某种方式组合它们。 Keep.{right, left, both, none}
是简单的函数,通过仅保留一个值或两个值或 none 来组合这些值。但是,即使您决定不保留它们,这也不会改变两个图都将具体化并生成值的事实。
我有一个简单的 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 or None) 告诉流实体化器应该保留流操作指定端的值。但我注意到,如果我将 Keep.Left 更改为 Keep.Right、Keep.Both 或事件 Keep.None,这不会改变执行结果中的任何内容:接收器将始终接收输出根据流量变换函数
我认为在流图中使用非 None 保持流阶段的值对于确保将值发送到接收器是必要的。我一定是误解了这个的意思,所以我的问题是为什么即使双方都禁用了物化,流仍然有效?您能否举例说明在左、右、两者之间更改保持值和 None 会影响到达接收器的值?
Keep.*
函数不会影响具体化过程本身,只会影响您从中得到的东西。
更具体地说,在实现时(即调用 run()
时),流的每个阶段(在您的示例中为源、流和汇)将 始终 被具体化 - 因此在引擎盖下产生具体化的价值。您可以从他们的最后一个类型参数中清楚地看到该值是什么。
为了方便用户,您很可能不会对所有这些都感兴趣,您可以相应地使用 Keep.*
到 select 什么 保留 大约。这直接体现在run()
的return类型上。
您混淆了流被具体化的事实和它具有具体化值的事实。
流(或更一般地说是图形)是流的蓝图。当您在可运行图上使用 run()
方法时,将使用此蓝图具体化一个流。这个流做任何它期望的事情,而不考虑物化值。
什么是物化值?当您使用 run()
方法时,会返回一个值。这就是您的流的物化价值。大多数时候(对于简单的内置阶段),物化值并不重要(它在 scala 中称为 NotUsed
,我不知道 .NET)。一个重要的例子是 Sink.ignore
被具体化为 Future[Done]
。它为您提供了具体化的特定流何时完全消耗其输入(或抛出错误)的句柄。更一般地说,物化值为您提供了一些关于您的流中发生的事情的间接信息(很抱歉这种说法含糊不清,但手头的原则太笼统了,我无法更明确)。
构建图表时,您将具有不同物化值的不同部分放在一起。由于您的可运行图只能有一个,因此您需要以某种方式组合它们。 Keep.{right, left, both, none}
是简单的函数,通过仅保留一个值或两个值或 none 来组合这些值。但是,即使您决定不保留它们,这也不会改变两个图都将具体化并生成值的事实。