可观察到循环推送值列表

时间:2016-01-18 09:03:24

标签: c# .net system.reactive

我想创建一个Observable,每隔t秒继续推送一个值列表。

例如,鉴于{1,2,3,4}订阅者应该得到这个:

1,2,3,4,1,2,3,4,1,2,3,4,1,2 ......

class Program
{
    static void Main()
    {
        var observable = Observable
            .Interval(TimeSpan.FromSeconds(3))
            .Zip(Observable.Range(1, 4)
            .Repeat(), (_, count) => count);

        observable.Subscribe(Console.WriteLine);

        Console.WriteLine("Finished!");
    }
}
  • 我已经研究过这个例子,它似乎有效,但是有一个非常讨厌的问题:Main方法永远不会结束执行!为什么? :(

  • 更糟糕的是,几分钟后,此控制台应用程序抛出OutOfMemoryException

4 个答案:

答案 0 :(得分:6)

这对我来说似乎是一个简单的错误.Repeat()

class Program
{
    static void Main()
    {
        var observable = Observable
            .Interval(TimeSpan.FromSeconds(3))
            .Zip(Observable.Range(1, 4), (_, count) => count)
            .Repeat();

        observable.Subscribe(Console.WriteLine);

        Console.WriteLine("Finished!");
        Console.ReadLine();
    }
}

现在:

  • 不阻止控制台完成
  • 不抛出OutOfMemoryException。

注意,不使用.Do(),没有自定义扩展方法,没有无限制的IEnumerables阻塞线程; - )

...还有一个没有Zip的替代实现,所以希望外行开发人员可以阅读和理解(也可以处置!):

class Program
{
    static void Main()
    {
        var observable = Observable
            .Interval(TimeSpan.FromSeconds(3))
            //.Zip(Observable.Range(1, 4), (_, count) => count)
            .Select(i=>i+1)
            .Take(4)
            .Repeat();

        using (observable.Subscribe(Console.WriteLine))
        {
            Console.WriteLine("Running...");
            Console.ReadLine();
        }
        Console.WriteLine("Finished!");
    }
}

答案 1 :(得分:5)

我删除了我建议的答案,正如Timothy&李的答案使用内置的Rx功能,更加优雅。不过,我会留下对这个问题的解释,因为我认为它很有用:

预期可观察量是推送序列,Zip将从更快的生成流中排队项目,同时等待来自第二个的值与下一个配对。当Obsevable.Range以订阅者可以处理的速度返回这些值时,这会填满所有内存并阻塞该线程。

答案 2 :(得分:2)

Charles Mager的回答已经解决了为什么你当前的代码没有工作,并提出了一种解决方法。这是我能想到修复它的最简单方法:

    var observable = Observable.Zip(
        Observable.Interval(TimeSpan.FromSeconds(3)),
        Enumerable.Range(1, 4).Repeat(),
        (_, count) => count);

This is just using the version of Zip that combines an IObservable and an IEnumerable.

Repeat扩展方法定义如下(与Charles Mager的回答相同):

public static IEnumerable<T> Repeat(this IEnumerable<T> source)
{
    while (true)
    {
        foreach (var item in source)
        {
            yield return item;
        }
    }
}

答案 3 :(得分:-1)

在System.Reactive.Concurrency命名空间中,有一些类和方法可以帮助进行调度。

以下代码是每3秒打印一个整数数组内容的粗略示例:

var numbers = new int[] { 1,2,3,4 };

var scs = new SynchronizationContextScheduler(new SynchronizationContext());
scs.SchedulePeriodic<int[]>(numbers, TimeSpan.FromSeconds(3), (n) => 
{
    foreach (var number in n)
    {
        Console.Write(number + " ");
    }
});

Console.ReadLine();

我不确定这是否是您正在寻找的但我希望它有所帮助。