コード例 #1
0
        public void PreferredMerge_must_prefer_selected_input_more_than_others()
        {
            const int numElements = 10000;
            var       preferred   =
                Source.From(Enumerable.Range(1, numElements).Select(_ => 1))
                .MapMaterializedValue <Task <IEnumerable <int> > >(_ => null);
            var aux = Source.From(Enumerable.Range(1, numElements).Select(_ => 2))
                      .MapMaterializedValue <Task <IEnumerable <int> > >(_ => null);

            var result = RunnableGraph.FromGraph(GraphDsl.Create(Sink.First <IEnumerable <int> >(), (b, sink) =>
            {
                var merge = b.Add(new MergePreferred <int>(3));
                b.From(preferred).To(merge.Preferred);
                b.From(merge.Out).Via(Flow.Create <int>().Grouped(numElements * 2)).To(sink.Inlet);
                b.From(aux).To(merge.In(0));
                b.From(aux).To(merge.In(1));
                b.From(aux).To(merge.In(2));
                return(ClosedShape.Instance);
            })).Run(Materializer);

            result.Wait(TimeSpan.FromSeconds(3)).Should().BeTrue();
            result.Result.Count(x => x == 1).Should().Be(numElements);
        }
コード例 #2
0
        public void ZipWithN_must_work_with_3_inputs()
        {
            var probe = this.CreateManualSubscriberProbe <int>();

            RunnableGraph.FromGraph(GraphDsl.Create(b =>
            {
                var zip = b.Add(new ZipWithN <int, int>(ints => ints.Sum(), 3));

                b.From(Source.Single(1)).To(zip.In(0));
                b.From(Source.Single(2)).To(zip.In(1));
                b.From(Source.Single(3)).To(zip.In(2));

                b.From(zip.Out).To(Sink.FromSubscriber(probe));
                return(ClosedShape.Instance);
            })).Run(Materializer);

            var subscription = probe.ExpectSubscription();

            subscription.Request(5);
            probe.ExpectNext(6);

            probe.ExpectComplete();
        }
コード例 #3
0
        public void A_Graph_with_materialized_value_must_expose_the_materialized_value_as_source(bool autoFusing)
        {
            var materializer = CreateMaterializer(autoFusing);

            var sub = this.CreateManualSubscriberProbe <int>();
            var f   = RunnableGraph.FromGraph(GraphDsl.Create(FoldSink, (b, fold) =>
            {
                var source = Source.From(Enumerable.Range(1, 10)).MapMaterializedValue(_ => Task.FromResult(0));
                b.From(source).To(fold);
                b.From(b.MaterializedValue)
                .Via(Flow.Create <Task <int> >().SelectAsync(4, x => x))
                .To(Sink.FromSubscriber(sub).MapMaterializedValue(_ => Task.FromResult(0)));
                return(ClosedShape.Instance);
            })).Run(materializer);

            f.Wait(TimeSpan.FromSeconds(3)).Should().BeTrue();
            var r1 = f.Result;

            sub.ExpectSubscription().Request(1);
            var r2 = sub.ExpectNext();

            r1.Should().Be(r2);
        }
コード例 #4
0
ファイル: GraphDslCompileSpec.cs プロジェクト: ziez/akka.net
        public void A_Graph_should_build_unzip_zip()
        {
            RunnableGraph.FromGraph(GraphDsl.Create(b =>
            {
                var zip    = b.Add(new Zip <int, string>());
                var unzip  = b.Add(new UnZip <int, string>());
                var sink   = Sink.AsPublisher <Tuple <int, string> >(false).MapMaterializedValue(_ => NotUsed.Instance);
                var source =
                    Source.From(new[]
                {
                    new KeyValuePair <int, string>(1, "a"), new KeyValuePair <int, string>(2, "b"),
                    new KeyValuePair <int, string>(3, "c")
                });


                b.From(source).To(unzip.In);
                b.From(unzip.Out0).Via(Flow.Create <int>().Select(x => x * 2)).To(zip.In0);
                b.From(unzip.Out1).To(zip.In1);
                b.From(zip.Out).To(sink);

                return(ClosedShape.Instance);
            })).Run(Materializer);
        }
コード例 #5
0
ファイル: BroadCastTest.cs プロジェクト: matej-hron/POC
        public static IRunnableGraph <NotUsed> BuildGraph()
        {
            Sink <User, NotUsed>          writeAuthors  = WriteAuthors2;
            Sink <HashTagEntity, NotUsed> writeHashTags = WriteHashTags2;

            Source <Tweet, NotUsed> tweetSource = TweetSource;

            return(RunnableGraph.FromGraph(GraphDsl.Create(b =>
            {
                var broadcast = b.Add(new Broadcast <Tweet>(2));
                b.From(tweetSource).To(broadcast.In);

                b.From(broadcast.Out(0))
                .Via(Flow.Create <Tweet>().Select(tweet => tweet.CreatedBy))
                .To(writeAuthors);

                b.From(broadcast.Out(1))
                .Via(Flow.Create <Tweet>().SelectMany(tweet => tweet.HashTags))
                .To(writeHashTags);

                return ClosedShape.Instance;
            })));
        }
コード例 #6
0
ファイル: BidiFlowSpec.cs プロジェクト: marcpiechura/akka.net
        public void A_BidiFlow_must_materialize_its_value()
        {
            var f = RunnableGraph.FromGraph(GraphDsl.Create(BidiMaterialized(), (b, bidi) =>
            {
                var flow1 = b.Add(Flow.Create <string>().Select(int.Parse).MapMaterializedValue(_ => Task.FromResult(0)));
                var flow2 =
                    b.Add(
                        Flow.Create <long>()
                        .Select(x => ByteString.FromString($"Hello {x}"))
                        .MapMaterializedValue(_ => Task.FromResult(0)));

                b.AddEdge(flow1.Outlet, bidi.Inlet1);
                b.AddEdge(bidi.Outlet2, flow1.Inlet);

                b.AddEdge(bidi.Outlet1, flow2.Inlet);
                b.AddEdge(flow2.Outlet, bidi.Inlet2);

                return(ClosedShape.Instance);
            })).Run(Materializer);

            f.Wait(TimeSpan.FromSeconds(3)).Should().BeTrue();
            f.Result.Should().Be(42);
        }
コード例 #7
0
        public void A_Flow_using_Join_must_allow_for_merge_cycle()
        {
            this.AssertAllStagesStopped(() =>
            {
                var source =
                    Source.Single("lonely traveler").MapMaterializedValue(_ => Task.FromResult(""));

                var flow1 = Flow.FromGraph(GraphDsl.Create(Sink.First <string>(), (b, sink) =>
                {
                    var merge     = b.Add(new Merge <string>(2));
                    var broadcast = b.Add(new Broadcast <string>(2, true));

                    b.From(source).To(merge.In(0));
                    b.From(merge.Out).To(broadcast.In);
                    b.From(broadcast.Out(0)).To(sink);
                    return(new FlowShape <string, string>(merge.In(1), broadcast.Out(1)));
                }));

                var t = flow1.Join(Flow.Create <string>()).Run(Materializer);
                t.Wait(TimeSpan.FromSeconds(3)).Should().BeTrue();
                t.Result.Should().Be("lonely traveler");
            }, Materializer);
        }
コード例 #8
0
        public void A_Merge_must_work_in_the_happy_case()
        {
            this.AssertAllStagesStopped(() =>
            {
                // Different input sizes(4 and 6)
                var source1 = Source.From(Enumerable.Range(0, 4));
                var source2 = Source.From(Enumerable.Range(4, 6));
                var source3 = Source.From(new List <int>());
                var probe   = this.CreateManualSubscriberProbe <int>();

                RunnableGraph.FromGraph(GraphDsl.Create(b =>
                {
                    var m1   = b.Add(new Merge <int>(2));
                    var m2   = b.Add(new Merge <int>(2));
                    var sink = Sink.FromSubscriber(probe);

                    b.From(source1).To(m1.In(0));
                    b.From(m1.Out).Via(Flow.Create <int>().Select(x => x * 2)).To(m2.In(0));
                    b.From(m2.Out).Via(Flow.Create <int>().Select(x => x / 2).Select(x => x + 1)).To(sink);
                    b.From(source2).To(m1.In(1));
                    b.From(source3).To(m2.In(1));

                    return(ClosedShape.Instance);
                })).Run(Materializer);

                var subscription = probe.ExpectSubscription();
                var collected    = new List <int>();
                for (var i = 1; i <= 10; i++)
                {
                    subscription.Request(1);
                    collected.Add(probe.ExpectNext());
                }

                collected.ShouldAllBeEquivalentTo(Enumerable.Range(1, 10));
                probe.ExpectComplete();
            }, Materializer);
        }
コード例 #9
0
        public void ZipWith_must_work_with_up_to_9_inputs()
        {
            // the jvm version uses 19 inputs but we have only 9

            this.AssertAllStagesStopped(() =>
            {
                var probe = this.CreateManualSubscriberProbe <string>();

                RunnableGraph.FromGraph(GraphDsl.Create(b =>
                {
                    Func <int, string, int, string, int, string, int, string, int, string> sum9 =
                        (i1, s1, i2, s2, i3, s3, i4, s4, i5) => i1 + s1 + i2 + s2 + i3 + s3 + i4 + s4 + i5;

                    // odd input ports will be Int, even input ports will be String
                    var zipWith = b.Add(ZipWith.Apply(sum9));

                    b.From(Source.Single(1)).To(zipWith.In0);
                    b.From(Source.Single("2")).To(zipWith.In1);
                    b.From(Source.Single(3)).To(zipWith.In2);
                    b.From(Source.Single("4")).To(zipWith.In3);
                    b.From(Source.Single(5)).To(zipWith.In4);
                    b.From(Source.Single("6")).To(zipWith.In5);
                    b.From(Source.Single(7)).To(zipWith.In6);
                    b.From(Source.Single("8")).To(zipWith.In7);
                    b.From(Source.Single(9)).To(zipWith.In8);
                    b.From(zipWith.Out).To(Sink.FromSubscriber(probe));

                    return(ClosedShape.Instance);
                })).Run(Materializer);

                var subscription = probe.ExpectSubscription();

                subscription.Request(1);
                probe.ExpectNext(Enumerable.Range(1, 9).Aggregate("", (s, i) => s + i));
                probe.ExpectComplete();
            }, Materializer);
        }
コード例 #10
0
ファイル: RoundRobinSpecs.cs プロジェクト: y4k/AkkaLibrary
        public Property RoundRobinDistributerSpecs()
        {
            return(Prop.ForAll <PositiveInt>(value =>
            {
                var probes = Enumerable.Range(0, value.Get).Select(_ => CreateTestProbe()).ToList();
                var sinks = probes.Select(p => Sink.ActorRef <int>(p, "completed")).ToList();

                using (var mat = Sys.Materializer())
                {
                    var graph = RunnableGraph.FromGraph(GraphDsl.Create(builder =>
                    {
                        var source = Source.From(Enumerable.Range(0, value.Get));

                        var roundRobin = builder.Add(new RoundRobinFanOut <int>(value.Get));

                        builder.From(source).To(roundRobin.In);

                        for (int i = 0; i < value.Get; i++)
                        {
                            builder.From(roundRobin.Out(i)).To(sinks[i]);
                        }

                        return ClosedShape.Instance;
                    }));

                    graph.Run(mat);

                    for (int i = 0; i < value.Get; i++)
                    {
                        var msg = probes[i].ExpectMsg <int>(TimeSpan.FromSeconds(3));
                        msg.Should().Be(i);
                        var completeMsg = probes[i].ExpectMsg <string>(TimeSpan.FromSeconds(3));
                        completeMsg.Should().Be("completed");
                    }
                }
            }));
        }
コード例 #11
0
        public void GraphDSLs_must_support_balance_merge_parallelization_layouts()
        {
            var elements = Enumerable.Range(0, 11).ToList();
            var task     = RunnableGraph.FromGraph(GraphDsl.Create(Sink.First <IEnumerable <int> >(), (b, sink) =>
            {
                var balance = b.Add(new Balance <int>(5));
                var merge   = b.Add(new Merge <int>(5));
                var source  = Source.From(elements).MapMaterializedValue <Task <IEnumerable <int> > >(_ => null);

                b.From(source).To(balance.In);

                for (var i = 0; i < 5; i++)
                {
                    b.From(balance.Out(i)).To(merge.In(i));
                }

                b.From(merge.Out).Via(Flow.Create <int>().Grouped(elements.Count * 2)).To(sink.Inlet);

                return(ClosedShape.Instance);
            })).Run(Materializer);

            task.Wait(TimeSpan.FromSeconds(3)).Should().BeTrue();
            task.Result.ShouldAllBeEquivalentTo(elements);
        }
コード例 #12
0
        CreateRunnableWethaerGraph <TMat>(Source <ITweet, TMat> tweetSource)
        {
            var formatUser = Flow.Create <IUser>()
                             .Select(Utils.FormatUser);
            var formatCoordinates = Flow.Create <ICoordinates>()
                                    .Select(Utils.FormatCoordinates);
            var formatTemperature = Flow.Create <decimal>()
                                    .Select(Utils.FormatTemperature);
            var writeSink = Sink.ForEach <string>(Console.WriteLine);

            // 1- Throttle at the same rate line 72 (Throttle(10))
            // 2- Throttle at different rate line 72 (Throttle(1))
            //     only 1 message because we have 1 stream source & broadcast = 2 channel with 1 request with 10 msg per second and 1 request with 1 msg per second... but we have only 1 stream source, so it cannot send messages to a different rate thus it sattisfy the lowest requirement.
            var graph = GraphDsl.Create(b =>
            {
                var broadcast = b.Add(new Broadcast <ITweet>(2));
                var merge     = b.Add(new Merge <string>(2));
                b.From(broadcast.Out(0))
                .Via(Flow.Create <ITweet>().Select(tweet => tweet.CreatedBy)
                     .Throttle(10, TimeSpan.FromSeconds(1), 1, ThrottleMode.Shaping))
                .Via(formatUser)
                .To(merge.In(0));
                b.From(broadcast.Out(1))
                .Via(Flow.Create <ITweet>().Select(tweet => tweet.Coordinates)
                     //.Buffer(10, OverflowStrategy.DropNew)
                     .Throttle(1, TimeSpan.FromSeconds(1), 1, ThrottleMode.Shaping))
                .Via(Flow.Create <ICoordinates>().SelectAsync(5, Utils.GetWeatherAsync))
                .Via(formatTemperature)
                .To(merge.In(1));

                return(new FlowShape <ITweet, string>(broadcast.In, merge.Out));
            });

            return(tweetSource.Where(x => x.Coordinates != null)
                   .Via(graph).To(writeSink));
        }
コード例 #13
0
        public void A_Balance_must_cancel_upstream_when_downstream_cancel()
        {
            this.AssertAllStagesStopped(() =>
            {
                var p1 = this.CreateManualPublisherProbe <int>();
                var c1 = this.CreateManualSubscriberProbe <int>();
                var c2 = this.CreateManualSubscriberProbe <int>();

                RunnableGraph.FromGraph(GraphDsl.Create(b =>
                {
                    var balance = b.Add(new Balance <int>(2));
                    var source  = Source.FromPublisher(p1.Publisher);
                    b.From(source).To(balance.In);
                    b.From(balance.Out(0)).To(Sink.FromSubscriber(c1));
                    b.From(balance.Out(1)).To(Sink.FromSubscriber(c2));
                    return(ClosedShape.Instance);
                })).Run(Materializer);

                var bsub = p1.ExpectSubscription();
                var sub1 = c1.ExpectSubscription();
                var sub2 = c2.ExpectSubscription();

                sub1.Request(1);
                p1.ExpectRequest(bsub, 16);
                bsub.SendNext(1);
                c1.ExpectNext(1);

                sub2.Request(1);
                bsub.SendNext(2);
                c2.ExpectNext(2);

                sub1.Cancel();
                sub2.Cancel();
                bsub.ExpectCancellation();
            }, Materializer);
        }
コード例 #14
0
        public void A_Balance_must_work_with_5_way_balance()
        {
            this.AssertAllStagesStopped(() =>
            {
                var sink = Sink.First <IEnumerable <int> >();
                var t    = RunnableGraph.FromGraph(GraphDsl.Create(sink, sink, sink, sink, sink, Tuple.Create,
                                                                   (b, s1, s2, s3, s4, s5) =>
                {
                    var balance = b.Add(new Balance <int>(5, true));
                    var source  = Source.From(Enumerable.Range(0, 15)).MapMaterializedValue <Tuple <Task <IEnumerable <int> >, Task <IEnumerable <int> >, Task <IEnumerable <int> >, Task <IEnumerable <int> >, Task <IEnumerable <int> > > >(_ => null);
                    b.From(source).To(balance.In);
                    b.From(balance.Out(0)).Via(Flow.Create <int>().Grouped(15)).To(s1);
                    b.From(balance.Out(1)).Via(Flow.Create <int>().Grouped(15)).To(s2);
                    b.From(balance.Out(2)).Via(Flow.Create <int>().Grouped(15)).To(s3);
                    b.From(balance.Out(3)).Via(Flow.Create <int>().Grouped(15)).To(s4);
                    b.From(balance.Out(4)).Via(Flow.Create <int>().Grouped(15)).To(s5);
                    return(ClosedShape.Instance);
                })).Run(Materializer);

                var task = Task.WhenAll(t.Item1, t.Item2, t.Item3, t.Item4, t.Item5);
                task.Wait(TimeSpan.FromSeconds(3)).Should().BeTrue();
                task.Result.SelectMany(l => l).ShouldAllBeEquivalentTo(Enumerable.Range(0, 15));
            }, Materializer);
        }
コード例 #15
0
        public Property UnzipEnumerableProps()
        {
            return(Prop.ForAll <PositiveInt>(value =>
            {
                using (var mat = Sys.Materializer())
                {
                    var probes = Enumerable.Range(0, value.Get).Select(x => CreateTestProbe()).ToList();

                    var graph = RunnableGraph.FromGraph(GraphDsl.Create(builder =>
                    {
                        var source = Source.From(Enumerable.Range(1, 1).Select(x => Enumerable.Range(0, value.Get).ToList()));

                        var unzipper = builder.Add(new UnzipEnumerable <List <int>, int>(x => x.ToImmutableList(), value.Get));

                        var sinks = probes.Select(p => Sink.ActorRef <int>(p, "completed")).ToList();

                        for (int i = 0; i < value.Get; i++)
                        {
                            builder.From(unzipper.Out(i)).To(sinks[i]);
                        }

                        builder.From(source).To(unzipper.In);

                        return ClosedShape.Instance;
                    }));

                    graph.Run(mat);

                    for (int i = 0; i < value.Get; i++)
                    {
                        var msg = probes[i].ExpectMsg <int>(TimeSpan.FromSeconds(3));
                        msg.Should().Be(i);
                    }
                }
            }));
        }
コード例 #16
0
        public void A_Flow_using_Join_must_allow_for_concat_cycle()
        {
            this.AssertAllStagesStopped(() =>
            {
                var flow = Flow.FromGraph(GraphDsl.Create(TestSource.SourceProbe <string>(this), Sink.First <string>(), Keep.Both, (b, source, sink) =>
                {
                    var concat    = b.Add(Concat.Create <string>(2));
                    var broadcast = b.Add(new Broadcast <string>(2, true));

                    b.From(source).To(concat.In(0));
                    b.From(concat.Out).To(broadcast.In);
                    b.From(broadcast.Out(0)).To(sink);
                    return(new FlowShape <string, string>(concat.In(1), broadcast.Out(1)));
                }));

                var tuple = flow.Join(Flow.Create <string>()).Run(Materializer);
                var probe = tuple.Item1;
                var t     = tuple.Item2;
                probe.SendNext("lonely traveler");
                t.Wait(TimeSpan.FromSeconds(3)).Should().BeTrue();
                t.Result.Should().Be("lonely traveler");
                probe.SendComplete();
            }, Materializer);
        }
コード例 #17
0
ファイル: GraphTests.cs プロジェクト: matej-hron/POC
        public void TheSameFlowIsMaterializedAsTwoConnections()
        {
            var topHeadSink    = Sink.Last <int>();
            var bottomHeadSink = Sink.First <int>();
            var sharedDoubler  = Flow.Create <int>().Select(x => x * 2);

            var g = RunnableGraph.FromGraph(GraphDsl.Create(topHeadSink, bottomHeadSink, Keep.Both,
                                                            (builder, topHs, bottomHs) =>
            {
                var broadcast = builder.Add(new Broadcast <int>(2));
                var source    = Source.From(Enumerable.Range(1, 10)).MapMaterializedValue <Tuple <Task <int>, Task <int> > >(_ => null);

                builder.From(source).To(broadcast.In);

                builder.From(broadcast.Out(0)).Via(sharedDoubler).To(topHs.Inlet);
                builder.From(broadcast.Out(1)).Via(sharedDoubler).To(bottomHs.Inlet);

                return(ClosedShape.Instance);
            }));

            var(a, b) = WithMaterializer(g.Run);
            Assert.That(a.Result, Is.EqualTo(20));
            Assert.That(b.Result, Is.EqualTo(2));
        }
コード例 #18
0
        public void GraphDSLs_Partial_must_be_able_to_build_and_reuse_simple_materializing_partial_graphs()
        {
            var doubler = GraphDsl.Create(Sink.First <IEnumerable <int> >(), (b, sink) =>
            {
                var broadcast = b.Add(new Broadcast <int>(3));
                var zip       = b.Add(ZipWith.Apply((int i, int i1) => i + i1));

                b.From(broadcast.Out(0)).To(zip.In0);
                b.From(broadcast.Out(1)).To(zip.In1);
                b.From(broadcast.Out(2)).Via(Flow.Create <int>().Grouped(100)).To(sink.Inlet);

                return(new FlowShape <int, int>(broadcast.In, zip.Out));
            });

            var t =
                RunnableGraph.FromGraph(GraphDsl.Create(doubler, doubler, Sink.First <IEnumerable <int> >(), Tuple.Create,
                                                        (b, d1, d2, sink) =>
            {
                var source =
                    Source.From(Enumerable.Range(1, 3))
                    .MapMaterializedValue <Tuple <Task <IEnumerable <int> >, Task <IEnumerable <int> >, Task <IEnumerable <int> > > >(_ => null);

                b.From(source).To(d1.Inlet);
                b.From(d1.Outlet).To(d2.Inlet);
                b.From(d2.Outlet).Via(Flow.Create <int>().Grouped(100)).To(sink.Inlet);

                return(ClosedShape.Instance);
            })).Run(Materializer);

            var task = Task.WhenAll(t.Item1, t.Item2, t.Item3);

            task.Wait(TimeSpan.FromSeconds(3)).Should().BeTrue();
            task.Result[0].ShouldAllBeEquivalentTo(new[] { 1, 2, 3 });
            task.Result[1].ShouldAllBeEquivalentTo(new[] { 2, 4, 6 });
            task.Result[2].ShouldAllBeEquivalentTo(new[] { 4, 8, 12 });
        }
コード例 #19
0
        public void A_Graph_with_materialized_value_must_work_properly_with_nesting_and_reusing(bool autoFusing)
        {
            var materializer = CreateMaterializer(autoFusing);

            var compositeSource1 = Source.FromGraph(GraphDsl.Create(FoldFeedbackSource, FoldFeedbackSource, Keep.Both,
                                                                    (b, s1, s2) =>
            {
                var zip = b.Add(new ZipWith <int, int, int>((i, i1) => i + i1));

                b.From(s1.Outlet).Via(Flow.Create <Task <int> >().SelectAsync(4, x => x)).To(zip.In0);
                b.From(s2.Outlet).Via(Flow.Create <Task <int> >().SelectAsync(4, x => x).Select(x => x * 100)).To(zip.In1);

                return(new SourceShape <int>(zip.Out));
            }));

            var compositeSource2 = Source.FromGraph(GraphDsl.Create(compositeSource1, compositeSource1, Keep.Both,
                                                                    (b, s1, s2) =>
            {
                var zip = b.Add(new ZipWith <int, int, int>((i, i1) => i + i1));

                b.From(s1.Outlet).To(zip.In0);
                b.From(s2.Outlet).Via(Flow.Create <int>().Select(x => x * 10000)).To(zip.In1);

                return(new SourceShape <int>(zip.Out));
            }));

            var t    = compositeSource2.ToMaterialized(Sink.First <int>(), Keep.Both).Run(materializer);
            var task = Task.WhenAll(t.Item1.Item1.Item1, t.Item1.Item1.Item2, t.Item1.Item2.Item1, t.Item1.Item2.Item2, t.Item2);

            task.Wait(TimeSpan.FromSeconds(3)).Should().BeTrue();
            task.Result[0].Should().Be(55);
            task.Result[1].Should().Be(55);
            task.Result[2].Should().Be(55);
            task.Result[3].Should().Be(55);
            task.Result[4].Should().Be(55555555);
        }
コード例 #20
0
        public void FlowGraphs_when_used_together_should_allow_connecting_source_to_sink_directly()
        {
            var probe    = TestSubscriber.CreateManualProbe <int>(this);
            var inSource = Source.AsSubscriber <int>();
            var outSink  = Sink.AsPublisher <int>(false);

            var source = Source.FromGraph(GraphDsl.Create(inSource, (b, src) => new SourceShape <int>(src.Outlet)));

            var sink = Sink.FromGraph(GraphDsl.Create(outSink, (b, s) => new SinkShape <int>(s.Inlet)));

            var t = RunnableGraph.FromGraph(GraphDsl.Create(source, sink, Keep.Both, (b, src, snk) =>
            {
                b.From(src.Outlet).To(snk.Inlet);
                return(ClosedShape.Instance);
            })).Run(Materializer);

            var subscriber = t.Item1;
            var publisher  = t.Item2;

            Source1.RunWith(Sink.AsPublisher <int>(false), Materializer).Subscribe(subscriber);
            publisher.Subscribe(probe);

            ValidateProbe(probe, 4, new[] { 0, 1, 2, 3 });
        }
コード例 #21
0
        public void FlowGraphs_when_turned_into_sources_should_be_reusable_multiple_times()
        {
            var probe = TestSubscriber.CreateManualProbe <int>(this);

            var source =
                Source.FromGraph(GraphDsl.Create(Source.From(Enumerable.Range(1, 5)),
                                                 (b, s) =>
            {
                var o = b.From(s.Outlet).Via(Flow.Create <int>().Select(x => x * 2));
                return(new SourceShape <int>(o.Out));
            }));

            RunnableGraph.FromGraph(GraphDsl.Create(source, source, Keep.Both, (b, s1, s2) =>
            {
                var merge = b.Add(new Merge <int>(2));
                b.From(s1.Outlet).To(merge.In(0));
                b.From(merge.Out)
                .To(Sink.FromSubscriber(probe).MapMaterializedValue(_ => Tuple.Create(NotUsed.Instance, NotUsed.Instance)));
                b.From(s2.Outlet).Via(Flow.Create <int>().Select(x => x * 10)).To(merge.In(1));
                return(ClosedShape.Instance);
            })).Run(Materializer);

            ValidateProbe(probe, 10, new[] { 2, 4, 6, 8, 10, 20, 40, 60, 80, 100 });
        }
コード例 #22
0
        public void Setup(BenchmarkContext context)
        {
            _system = ActorSystem.Create("Test");
            var settings =
                ActorMaterializerSettings.Create(_system)
                .WithFuzzingMode(false)
                .WithSyncProcessingLimit(int.MaxValue)
                .WithAutoFusing(false);     // We fuse manually in this test in the setup

            _materializer = _system.Materializer(settings);
            _testElements = Enumerable.Repeat(0, ElementCount).Select(i => new MutableElement(i)).ToArray();
            var testSource    = Source.FromGraph(new TestSource(_testElements));
            var testSink      = Sink.FromGraph(new CompletionLatch());
            var identityStage = new IdentityStage();

            _singleIdentity    = Fuse(testSource.Via(identityStage).ToMaterialized(testSink, Keep.Right));
            _chainOfIdentities =
                Fuse(
                    testSource.Via(identityStage)
                    .Via(identityStage)
                    .Via(identityStage)
                    .Via(identityStage)
                    .Via(identityStage)
                    .Via(identityStage)
                    .Via(identityStage)
                    .Via(identityStage)
                    .Via(identityStage)
                    .Via(identityStage)
                    .ToMaterialized(testSink, Keep.Right));

            _singleSelect = Fuse(testSource.Select(Add).ToMaterialized(testSink, Keep.Right));

            _chainOfSelects = Fuse(
                testSource.Select(Add)
                .Select(Add)
                .Select(Add)
                .Select(Add)
                .Select(Add)
                .Select(Add)
                .Select(Add)
                .Select(Add)
                .Select(Add)
                .Select(Add)
                .ToMaterialized(testSink, Keep.Right));

            _repeatTakeSelectAndAggregate =
                Fuse(Source.Repeat(new MutableElement(0))
                     .Take(ElementCount)
                     .Select(Add)
                     .Select(Add)
                     .Aggregate(new MutableElement(0), (acc, x) =>
            {
                acc.Value += x.Value;
                return(acc);
            }).ToMaterialized(testSink, Keep.Right));

            _singleBuffer =
                Fuse(testSource.Buffer(10, OverflowStrategy.Backpressure).ToMaterialized(testSink, Keep.Right));

            _chainOfBuffers =
                Fuse(
                    testSource.Buffer(10, OverflowStrategy.Backpressure)
                    .Buffer(10, OverflowStrategy.Backpressure)
                    .Buffer(10, OverflowStrategy.Backpressure)
                    .Buffer(10, OverflowStrategy.Backpressure)
                    .Buffer(10, OverflowStrategy.Backpressure)
                    .Buffer(10, OverflowStrategy.Backpressure)
                    .Buffer(10, OverflowStrategy.Backpressure)
                    .Buffer(10, OverflowStrategy.Backpressure)
                    .Buffer(10, OverflowStrategy.Backpressure)
                    .Buffer(10, OverflowStrategy.Backpressure)
                    .ToMaterialized(testSink, Keep.Right));

            var broadcastZipFLow = Flow.FromGraph(GraphDsl.Create(b =>
            {
                var bcast = b.Add(new Broadcast <MutableElement>(2));
                var zip   = b.Add(new Zip <MutableElement, MutableElement>());

                b.From(bcast).To(zip.In0);
                b.From(bcast).To(zip.In1);
                var outlet =
                    b.From(zip.Out).Via(Flow.Create <(MutableElement, MutableElement)>().Select(t => t.Item1));
                return(new FlowShape <MutableElement, MutableElement>(bcast.In, outlet.Out));
            }));

            var balanceMergeFlow = Flow.FromGraph(GraphDsl.Create(b =>
            {
                var balance = b.Add(new Balance <MutableElement>(2));
                var merge   = b.Add(new Merge <MutableElement>(2));

                b.From(balance).To(merge);
                b.From(balance).To(merge);

                return(new FlowShape <MutableElement, MutableElement>(balance.In, merge.Out));
            }));

            _broadcastZip = Fuse(testSource.Via(broadcastZipFLow).ToMaterialized(testSink, Keep.Right));

            _balanceMerge = Fuse(testSource.Via(balanceMergeFlow).ToMaterialized(testSink, Keep.Right));

            _broadcastZipBalanceMerge = Fuse(testSource.Via(broadcastZipFLow).Via(balanceMergeFlow).ToMaterialized(testSink, Keep.Right));
        }
コード例 #23
0
        public async Task RunnableGraphMadeOfBackpressuredQueueAndActorRefWithAckWorksAsExpected()
        {
            const int MAX = 4;

            Source <int, ISourceQueueWithComplete <int> > source = Source.Queue <int>(MAX, OverflowStrategy.Backpressure);
            TestProbe probe = CreateTestProbe();
            Sink <IEnumerable <int>, NotUsed> sink = Sink.ActorRefWithAck <IEnumerable <int> >(probe.Ref, "init", "ack", "complete");

            RunnableGraph <ISourceQueueWithComplete <int> > rg = RunnableGraph.FromGraph(GraphDsl.Create(source, sink, Keep.Left,
                                                                                                         (builder, source_, sink_) =>
            {
                UniformFanOutShape <int, int> broadcaster = builder.Add(new Broadcast <int>(2));
                UniformFanInShape <IEnumerable <int>, IEnumerable <int> > merger = builder.Add(new Merge <IEnumerable <int> >(2));

                var f1 = Flow.Create <int>().Aggregate(new List <int>(),
                                                       (agg, curr) =>
                {
                    agg.Add(curr);
                    return(agg);
                }).Select(list => list.AsEnumerable());
                var f2 = Flow.Create <int>().Aggregate(new List <int>(),
                                                       (agg, curr) =>
                {
                    agg.Add(curr);
                    return(agg);
                }).Select(list => list.AsEnumerable());

                builder.From(source_).To(broadcaster.In);
                builder.From(broadcaster.Out(0)).Via(f1).To(merger.In(0));
                builder.From(broadcaster.Out(1)).Via(f2).To(merger.In(1));
                builder.From(merger.Out).To(sink_);

                return(ClosedShape.Instance);
            }));

            ISourceQueueWithComplete <int> q = rg.Run(_materializer);

            probe.ExpectMsg <string>((msg, sender) =>
            {
                if (msg != "init")
                {
                    throw new InvalidOperationException($"Expected: init. Found: {msg}");
                }
                sender.Tell("ack");
            });
            await q.OfferAsync(2);

            await q.OfferAsync(4);

            await q.OfferAsync(8);

            await q.OfferAsync(16);

            q.Complete();
            await q.WatchCompletionAsync();

            probe.ExpectMsg <IEnumerable <int> >((msg, sender) =>
            {
                Assert.Equal(new[] { 2, 4, 8, 16 }.AsEnumerable(), msg);
                sender.Tell("ack");
            });
            probe.ExpectMsg <IEnumerable <int> >((msg, sender) =>
            {
                Assert.Equal(new[] { 2, 4, 8, 16 }.AsEnumerable(), msg);
                sender.Tell("ack");
            });

            probe.ExpectMsg("complete");
            probe.ExpectNoMsg();
        }
コード例 #24
0
        private static RunnableGraph <ISourceQueueWithComplete <ChannelData <float> > > CreateGraph(IActorRef target, List <ChannelAdjusterConfig> configs, ChannelData <float> sample)
        {
            /*
             *  Digital Merger is only necessary when there are additional digitals created and the same goes for the
             *  Broadcast following the Analog Splitter. A broadcast is only required when the analog channel is produces
             *  the additional digitals. Otherwise the analog is pushed straight to the merger
             +---------------+--------------+-----------------------------------------------------------------------+
             |               |              |                     SyncData                           |              |
             |               |              +-------------+----------------+-------------------------+              |
             |  QueueSource  | Channel Data |             |    FilterFlow           |                | Channel Data |
             |               |    Splitter  |    Analog   |  ================       |     Analog     |              |
             |               |              |   Splitter  |  Broadcast => Filter    |     Merger     |              |
             |               |              |             |         ----------------+----------------+              |
             |               |              |             |         \=> -FullScale  |                |              |
             |               |              |             |         \=> +FullScale  |    Digital     |              |
             |               |              |             |         \=> FlatLining  |     Merger     |              |
             |               |              +-------------+-------------------------+                |              |
             |               |              |    Digitals                           |                |              |
             +---------------+--------------+-----------------------------------------------------------------------+
             */

            var indices = GetIndices(sample, configs);
            var number  = indices.Count();

            var temporalOffsets = configs.Select(x => - x.TemporalOffset).Append(0);

            var temp        = temporalOffsets.Select(x => x - temporalOffsets.Min()).ToList();
            var skipIndices = temp.Take(temp.Count - 1).ToList();
            var zerothIndex = temp.Last();



            var bufferSize      = temp.Max() + 1;
            var skipFlowsNeeded = skipIndices.Any(x => x != 0);

            var graph = GraphDsl.Create(Source.Queue <ChannelData <float> >(10000, OverflowStrategy.Backpressure), (builder, source) =>
            {
                //Split channel data into sync data, analogs and digitals
                var channelDataSplitter = new UnzipWith <
                    ChannelData <float>,
                    ISyncData,
                    IReadOnlyList <DataChannel <float> >,
                    IReadOnlyList <DataChannel <bool> >
                    >(cd => Tuple.Create(cd as ISyncData, cd.Analogs, cd.Digitals));
                var channelDataSplitterShape = builder.Add(channelDataSplitter);

                //Split, filter and reorder the analog channels into the required data channels
                var analogSplitter = new UnzipEnumerable <
                    IReadOnlyList <DataChannel <float> >,
                    DataChannel <float>
                    >(list => indices.Select(i => list[i]).ToImmutableList(), number
                      );
                var analogSplitterShape = builder.Add(analogSplitter);

                //Re-combine the filtered analog channels
                var analogMerger      = new ZipN <DataChannel <float> >(number);
                var analogMergerShape = builder.Add(analogMerger);

                //Digital additional flows
                var additionalDigitalFlows = new List <FlowShape <DataChannel <float>, DataChannel <bool> > >();

                //Create the appropriate analog filtering flows.
                for (int i = 0; i < configs.Count(); i++)
                {
                    var skipValue = skipIndices[i];
                    //Create new flows for the analogs
                    switch (configs[i].Option)
                    {
                    // 1a) Each cfg generates one analog flow...
                    case FilterOption.PassThrough:
                        if (skipFlowsNeeded)
                        {
                            builder.From(analogSplitterShape.Out(i))
                            .Via(
                                builder.Add(
                                    Flow.Create <DataChannel <float> >()
                                    .Buffer(bufferSize, OverflowStrategy.Backpressure)
                                    .Skip(skipValue)
                                    .Log("AnalogLog")
                                    )
                                )
                            .To(analogMergerShape.In(i));
                        }
                        else
                        {
                            // Pass through channels can be connected straight from the splitter to the merger.
                            builder.From(analogSplitterShape.Out(i)).To(analogMergerShape.In(i));
                        }
                        break;

                    case FilterOption.Filter:
                        // Filtered channels create a single flow and connected from the splitter to the merger.
                        var scale  = configs[i].Scale;
                        var offset = configs[i].Offset;

                        var filterFlow = skipFlowsNeeded ?
                                         Flow.Create <DataChannel <float> >()
                                         .Buffer(bufferSize, OverflowStrategy.Backpressure)
                                         .Skip(skipValue)
                                         .Select(x => new DataChannel <float>(x.Name, x.Value * scale + offset, x.Units))
                                                    :
                                         Flow.Create <DataChannel <float> >()
                                         .Select(x => new DataChannel <float>(x.Name, x.Value * scale + offset, x.Units));

                        builder.From(analogSplitterShape.Out(i)).Via(builder.Add(filterFlow)).To(analogMergerShape.In(i));
                        break;

                    // 1b) OR One analog flow and 3 additional digital flows.
                    case FilterOption.CreateDigitals:
                        // Filtered channels that create digitals creates a broadcaster for the analog channel first...
                        var analogBroadcaster = new Broadcast <DataChannel <float> >(4);

                        // ...then three flows for the digitals
                        var d1Flow = builder.Add(Flow.Create <DataChannel <float> >().Select(x => new DataChannel <bool>($"{x.Name}_+FullScale", false)));
                        var d2Flow = builder.Add(Flow.Create <DataChannel <float> >().Select(x => new DataChannel <bool>($"{x.Name}_-FullScale", false)));
                        var d3Flow = builder.Add(Flow.Create <DataChannel <float> >().Select(x => new DataChannel <bool>($"{x.Name}_Flatlining", false)));

                        // ...add the digital flow shapes to be connected later
                        additionalDigitalFlows.Add(d1Flow);
                        additionalDigitalFlows.Add(d2Flow);
                        additionalDigitalFlows.Add(d3Flow);

                        // ...create the broadcaster shape
                        var analogBroadcasterShape = builder.Add(analogBroadcaster);

                        // ...create the filter flow and connect the broadcaster to the merger via the filter
                        var scaler    = configs[i].Scale;
                        var offsetter = configs[i].Offset;
                        var filter    = skipFlowsNeeded ?
                                        Flow.Create <DataChannel <float> >()
                                        .Buffer(bufferSize, OverflowStrategy.Backpressure)
                                        .Skip(skipValue)
                                        .Select(x => new DataChannel <float>(x.Name, x.Value * scaler + offsetter, x.Units))
                                                :
                                        Flow.Create <DataChannel <float> >()
                                        .Select(x => new DataChannel <float>(x.Name, x.Value * scaler + offsetter, x.Units));


                        // ...link the analog splitter output to the broadcaster
                        builder.From(analogSplitterShape.Out(i))
                        .Via(filter)
                        .To(analogBroadcasterShape);

                        builder.From(analogBroadcasterShape.Out(0)).To(analogMergerShape.In(i));
                        // ...link the broadcaster channels to the additional digital flows
                        builder.From(analogBroadcasterShape.Out(1)).Via(d1Flow);
                        builder.From(analogBroadcasterShape.Out(2)).Via(d2Flow);
                        builder.From(analogBroadcasterShape.Out(3)).Via(d3Flow);
                        break;

                    case FilterOption.NotSet:
                        throw new ArgumentException("Filter Option Not Set is not allowed.");
                    }
                }

                //Merge everything back together
                var channelDataMerger = ZipWith.Apply <
                    ISyncData,
                    IImmutableList <DataChannel <float> >,
                    IReadOnlyList <DataChannel <bool> >,
                    ChannelData <float>
                    >(
                    (sync, analogs, digitals) => new ChannelData <float>
                    (
                        analogs,
                        digitals,
                        sync.TimeStamp,
                        sync.TachometerCount,
                        sync.MasterSyncIncrement,
                        sync.MasterSyncState,
                        sync.SampleIndex
                    )
                    );
                var channelDataMergerShape = builder.Add(channelDataMerger);

                //Sink
                var sink      = Sink.ActorRef <ChannelData <float> >(target, false);
                var sinkShape = builder.Add(sink);

                //_________Link stages_________

                //=====Source=====
                //Source to the channel data splitter
                if (skipFlowsNeeded)
                {
                    builder.From(source)
                    .Via(builder.Add(Flow.Create <ChannelData <float> >().Buffer(bufferSize, OverflowStrategy.Backpressure)))
                    .To(channelDataSplitterShape.In);

                    //=====Splitter=====
                    //Splitter sync data to merger.
                    builder.From(channelDataSplitterShape.Out0)
                    .Via(builder.Add(Flow.Create <ISyncData>().Buffer(bufferSize, OverflowStrategy.Backpressure).Skip(zerothIndex)))
                    .To(channelDataMergerShape.In0);

                    //Splitter analogs to analog splitter.
                    builder.From(channelDataSplitterShape.Out1)
                    .Via(builder.Add(Flow.Create <IReadOnlyList <DataChannel <float> > >().Buffer(bufferSize, OverflowStrategy.Backpressure)))
                    .To(analogSplitterShape.In);

                    //=====AdditionalDigitalFlows=====
                    if (additionalDigitalFlows.Count > 0)
                    {
                        // Additonal Digital Merger
                        var additionalDigitalMerger      = new ZipWithN <DataChannel <bool>, IImmutableList <DataChannel <bool> > >(channel => channel, additionalDigitalFlows.Count);
                        var additionalDigitalMergerShape = builder.Add(additionalDigitalMerger);

                        //Combine the input digitals with the generated additional digitals
                        var digitalMerger      = ZipWith.Apply <List <DataChannel <bool> >, ImmutableList <DataChannel <bool> >, IReadOnlyList <DataChannel <bool> > >((channel1, channel2) => channel1.Concat(channel2).ToList());
                        var digitalMergerShape = builder.Add(digitalMerger);

                        //Splitter digitals to digital merger.
                        builder.From(channelDataSplitterShape.Out2)
                        .Via(builder.Add(Flow.Create <IReadOnlyList <DataChannel <bool> > >().Buffer(bufferSize, OverflowStrategy.Backpressure)))
                        .To(digitalMergerShape.In0);

                        // Merge all additional flows together.
                        for (int i = 0; i < additionalDigitalFlows.Count; i++)
                        {
                            builder.From(additionalDigitalFlows[i]).To(additionalDigitalMergerShape.In(i));
                        }
                        //Additional digitals to digital merger
                        builder.From(additionalDigitalMergerShape.Out).To(digitalMergerShape.In1);

                        //=====DigitalMerger=====
                        //Digital merger to channel data merger
                        builder.From(digitalMergerShape.Out).To(channelDataMergerShape.In2);
                    }
                    else
                    {
                        // Splitter digitals to final merger.
                        builder.From(channelDataSplitterShape.Out2)
                        .Via(builder.Add(Flow.Create <IReadOnlyList <DataChannel <bool> > >().Buffer(bufferSize, OverflowStrategy.Backpressure)))
                        .To(channelDataMergerShape.In2);
                    }

                    // Analog merger to final merger.
                    builder.From(analogMergerShape.Out).To(channelDataMergerShape.In1);


                    //=====Merger=====
                    //Channel Data Merger to sink
                    builder.From(channelDataMergerShape.Out).To(sinkShape);
                }
                else
                {
                    builder.From(source).To(channelDataSplitterShape.In);

                    //=====Splitter=====
                    //Splitter sync data to merger.
                    builder.From(channelDataSplitterShape.Out0).To(channelDataMergerShape.In0);
                    //Splitter analogs to analog splitter.
                    builder.From(channelDataSplitterShape.Out1).To(analogSplitterShape.In);

                    //=====AdditionalDigitalFlows=====
                    if (additionalDigitalFlows.Count > 0)
                    {
                        // Additonal Digital Merger
                        var additionalDigitalMerger      = new ZipWithN <DataChannel <bool>, IImmutableList <DataChannel <bool> > >(channel => channel, additionalDigitalFlows.Count);
                        var additionalDigitalMergerShape = builder.Add(additionalDigitalMerger);

                        //Combine the input digitals with the generated additional digitals
                        var digitalMerger      = ZipWith.Apply <List <DataChannel <bool> >, ImmutableList <DataChannel <bool> >, IReadOnlyList <DataChannel <bool> > >((channel1, channel2) => channel1.Concat(channel2).ToList());
                        var digitalMergerShape = builder.Add(digitalMerger);

                        //Splitter digitals to digital merger.
                        builder.From(channelDataSplitterShape.Out2).To(digitalMergerShape.In0);

                        // Merge all additional flows together.
                        for (int i = 0; i < additionalDigitalFlows.Count; i++)
                        {
                            builder.From(additionalDigitalFlows[i]).To(additionalDigitalMergerShape.In(i));
                        }
                        //Additional digitals to digital merger
                        builder.From(additionalDigitalMergerShape.Out).To(digitalMergerShape.In1);

                        //=====DigitalMerger=====
                        //Digital merger to channel data merger
                        builder.From(digitalMergerShape.Out).To(channelDataMergerShape.In2);
                    }
                    else
                    {
                        // Splitter digitals to final merger.
                        builder.From(channelDataSplitterShape.Out2).To(channelDataMergerShape.In2);
                    }

                    // Analog merger to final merger.
                    builder.From(analogMergerShape.Out).To(channelDataMergerShape.In1);


                    //=====Merger=====
                    //Channel Data Merger to sink
                    builder.From(channelDataMergerShape.Out).To(sinkShape);
                }

                return(ClosedShape.Instance);
            });

            return(RunnableGraph.FromGraph(graph));
        }