Java Akka流丢弃消息?

Java Akka流丢弃消息?,java,akka,akka-stream,Java,Akka,Akka Stream,我是阿克卡溪的新手。我在Java中使用它。(akka-stream_2.12,版本:2.5.14) 我写了以下课程: package main; import java.io.IOException; import akka.actor.ActorSystem; import akka.stream.ActorMaterializer; import akka.stream.Materializer; import akka.stream.OverflowStrategy; import a

我是阿克卡溪的新手。我在Java中使用它。(akka-stream_2.12,版本:2.5.14)

我写了以下课程:

package main;

import java.io.IOException;

import akka.actor.ActorSystem;
import akka.stream.ActorMaterializer;
import akka.stream.Materializer;
import akka.stream.OverflowStrategy;
import akka.stream.javadsl.Sink;
import akka.stream.javadsl.Source;
import akka.stream.javadsl.SourceQueueWithComplete;

public class AkkaTest {
    public static void main(String[] args) throws IOException, InterruptedException {
        final ActorSystem actorSystem = ActorSystem.create("VehicleSystem");
        final Materializer materializer = ActorMaterializer.create(actorSystem);

        SourceQueueWithComplete<Object> componentA_outPort1 = 
                Source.<Object>queue(100, OverflowStrategy.backpressure()).async()
                    .to(Sink.foreach(str -> System.out.println(str)))
                    .run(materializer);

        for(int i=1; i<100000; i++)
            componentA_outPort1.offer("Akka rocks: " + i);

        System.in.read();
        actorSystem.terminate();
        System.out.println("Done.");
    }
}
packagemain;
导入java.io.IOException;
导入akka.actor.actor系统;
进口akka.stream.actormatarializer;
导入akka.stream.Materializer;
导入akka.stream.OverflowStrategy;
导入akka.stream.javadsl.Sink;
导入akka.stream.javadsl.Source;
导入akka.stream.javadsl.SourceQueueWithComplete;
公共类AkkaTest{
公共静态void main(字符串[]args)引发IOException、InterruptedException{
最终ActorSystem ActorSystem=ActorSystem.create(“车辆系统”);
final-Materializer-Materializer=ActorMaterializer.create(actorSystem);
SourceQueueWithComplete组件A_outPort1=
queue(100,OverflowStrategy.backpressure()).async()
.to(Sink.foreach(str->System.out.println(str)))
.run(物化器);

对于(int i=1;i这里问题的第一个提示是“完成”并没有在末尾打印到控制台上。相反,它打印在开头或“Akka rocks”打印之间的某个地方

这是因为
SourceQueue.offer
是异步的。它返回一个
CompletionStage
,您不需要等待它的完成。一些流元素“丢失”的事实可以用以下部分来解释,具体如下:

此外,当使用背压溢出策略时:-如果缓冲区已满,则在缓冲区中有空间之前不会完成未来-在这种情况下,在未来完成之前调用要约将返回失败的未来

您可以通过执行以下操作来验证这一点:

SourceQueueWithComplete<Object> componentA_outPort1 = 
    Source.<Object>queue(100, OverflowStrategy.backpressure()).async()
        .to(Sink.foreach(str -> System.out.println(str)))
        .run(materializer);

for (int i=1; i<100000; i++) {
  CompletionStage<QueueOfferResult> result = componentA_outPort1.offer("Akka rocks: " + i);
  System.out.println(result);
}

对于更复杂的情况,考虑源的其他静态方法,如“代码>源代码”,从中获取迭代或“代码>源”。FruteReals< /C> >

两件事:

  • 源队列
    提供信息的惯用方法是使用另一个
    (正如佩德罗在回答中提到的)
  • 您可能在流完成处理之前终止actor系统
  • 一旦接收器的物化值完成,请关闭系统:

    import java.util.concurrent.CompletionStage;
    
    import akka.Done;
    import akka.japi.Pair;
    import akka.stream.javadsl.Keep;
    import akka.stream.javadsl.RunnableGraph;
    // other imports...
    
    Sink<String, CompletionStage<Done>> sink =
      Sink.foreach(str -> System.out.println(str));
    
    Source<String, SourceQueueWithComplete<String>> outPort =
      Source.<String>queue(100, OverflowStrategy.backpressure()).async();
    
    RunnableGraph<Pair<SourceQueueWithComplete<String>, CompletionStage<Done>>> stream =
      outPort.toMat(sink, Keep.both());
    
    Pair<SourceQueueWithComplete<String>, CompletionStage<Done>> pair = stream.run();
    
    Source.range(1, 100000)
      .map(i -> "Akka rocks: " + i)
      .mapAsync(1, s -> pair.first().offer(s))
      .runWith(Sink.ignore(), materializer);
    
    pair.second().thenRun(() -> actorSystem.terminate());
    
    import java.util.concurrent.CompletionStage;
    进口阿克卡。完成;
    进口akka.japi.Pair;
    导入akka.stream.javadsl.Keep;
    导入akka.stream.javadsl.RunnableGraph;
    //其他进口。。。
    水槽=
    Sink.foreach(str->System.out.println(str));
    源输出端口=
    queue(100,OverflowStrategy.backpressure()).async();
    RunnableGraph流=
    toMat(sink,Keep.both());
    Pair Pair=stream.run();
    来源.范围(11000)
    .地图(i->“阿克卡岩石:”+i)
    .mapsync(1,s->pair.first().offer)
    .runWith(Sink.ignore(),物化器);
    然后运行(()->actorSystem.terminate());
    
    寻求调试帮助的问题(“为什么此代码不起作用?”)必须包括所需的行为、特定的问题或错误以及在问题本身中重现问题所需的最短代码。没有明确问题陈述的问题对其他读者没有用处。请参阅:。我编辑了示例。现在更好了吗?我发布的示例是我试图实现的结果的简化版本。在实际代码中,我想将事件发送到流,而事件可能在不同的时间到达。因此,一个具有范围的简单源是不够的。我还肯定需要一个异步边界。使用.mapsync的解决方案与使用.async()的解决方案不同吗,关于异步处理?使用
    mapsync
    和使用
    定义异步边界。async
    是不同的。请阅读本文了解更多详细信息。您可能希望尝试调整并行级别(第一个参数为
    mapsync
    )。
    Source.range(1,  1000).map(i -> "Akka rocks: " + i)
    
    import java.util.concurrent.CompletionStage;
    
    import akka.Done;
    import akka.japi.Pair;
    import akka.stream.javadsl.Keep;
    import akka.stream.javadsl.RunnableGraph;
    // other imports...
    
    Sink<String, CompletionStage<Done>> sink =
      Sink.foreach(str -> System.out.println(str));
    
    Source<String, SourceQueueWithComplete<String>> outPort =
      Source.<String>queue(100, OverflowStrategy.backpressure()).async();
    
    RunnableGraph<Pair<SourceQueueWithComplete<String>, CompletionStage<Done>>> stream =
      outPort.toMat(sink, Keep.both());
    
    Pair<SourceQueueWithComplete<String>, CompletionStage<Done>> pair = stream.run();
    
    Source.range(1, 100000)
      .map(i -> "Akka rocks: " + i)
      .mapAsync(1, s -> pair.first().offer(s))
      .runWith(Sink.ignore(), materializer);
    
    pair.second().thenRun(() -> actorSystem.terminate());