我想创建一个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
!
答案 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();
}
}
现在:
注意,不使用.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();
我不确定这是否是您正在寻找的但我希望它有所帮助。