Asynchronous 实现一个IObservable来计算Pi的位数
这是一个学术性的练习,我对反应式扩展还不熟悉,并试图了解这项技术。我给自己设定了一个目标,就是制作一个IObservable,它返回Pi的连续数字(出于不相关的原因,我恰好对Pi非常感兴趣)。反应式扩展包含用于创建可观察对象的操作符,它们给出的指导是您应该“几乎不需要创建自己的IObsevable”。但我不知道如何使用现成的操作符和方法来实现这一点。让我再解释一下 我计划用它来扩展Arctan的泰勒级数。为了得到π的下一个数字,我将在序列中展开更多的项 因此,我需要异步进行序列扩展,偶尔向IObserver抛出下一个计算数字。我显然不想重新开始计算每一个新的数字Asynchronous 实现一个IObservable来计算Pi的位数,asynchronous,system.reactive,pi,Asynchronous,System.reactive,Pi,这是一个学术性的练习,我对反应式扩展还不熟悉,并试图了解这项技术。我给自己设定了一个目标,就是制作一个IObservable,它返回Pi的连续数字(出于不相关的原因,我恰好对Pi非常感兴趣)。反应式扩展包含用于创建可观察对象的操作符,它们给出的指导是您应该“几乎不需要创建自己的IObsevable”。但我不知道如何使用现成的操作符和方法来实现这一点。让我再解释一下 我计划用它来扩展Arctan的泰勒级数。为了得到π的下一个数字,我将在序列中展开更多的项 因此,我需要异步进行序列扩展,偶尔向IOb
有没有一种方法可以使用RX的内置操作符实现这种行为,或者我必须从头开始编写IObservable?什么样的策略会让人想到呢?对于这样的事情,最简单的方法就是使用一个。Subject既是一个IObservable,又是一个IObserver,这听起来有点奇怪,但它允许您这样使用它们:
class PiCalculator
{
private readonly Subject<int> resultStream = new Subject<int>();
public IObservable<int> ResultStream
{
get { return resultStream; }
}
public void Start()
{
// Whatever the algorithm actually is
for (int i = 0; i < 1000; i++)
{
resultStream.OnNext(i);
}
}
}
对于这种情况,最简单的方法是使用。Subject既是一个IObservable,又是一个IObserver,这听起来有点奇怪,但它允许您这样使用它们:
class PiCalculator
{
private readonly Subject<int> resultStream = new Subject<int>();
public IObservable<int> ResultStream
{
get { return resultStream; }
}
public void Start()
{
// Whatever the algorithm actually is
for (int i = 0; i < 1000; i++)
{
resultStream.OnNext(i);
}
}
}
最简单的方法是创建一个
可枚举的
,然后将其转换为:
IEnumerable<int> Pi()
{
// algorithm here
for (int i = 0; i < 1000; i++)
{
yield return i;
}
}
如果要使其成为热门(每个人都共享相同的基础计算),可以执行以下操作:
var hot = cold.Publish().RefCount();
这将在第一个订户之后开始计算,并在所有订户都断开连接时停止计算。下面是一个简单的测试:
hot.Subscribe(p => Console.WriteLine("hot1: " + p));
Thread.Sleep(5);
hot.Subscribe(p => Console.WriteLine("hot2: " + p));
这应该会显示
hot1
仅打印一段时间,然后hot2
在短暂等待后加入,但打印相同的数字。如果使用cold
完成此操作,则两个订阅将分别从0开始。最简单的方法是创建一个可枚举的
,然后将其转换为:
IEnumerable<int> Pi()
{
// algorithm here
for (int i = 0; i < 1000; i++)
{
yield return i;
}
}
如果要使其成为热门(每个人都共享相同的基础计算),可以执行以下操作:
var hot = cold.Publish().RefCount();
这将在第一个订户之后开始计算,并在所有订户都断开连接时停止计算。下面是一个简单的测试:
hot.Subscribe(p => Console.WriteLine("hot1: " + p));
Thread.Sleep(5);
hot.Subscribe(p => Console.WriteLine("hot2: " + p));
这应该会显示
hot1
仅打印一段时间,然后hot2
在短暂等待后加入,但打印相同的数字。如果使用cold
,这两个订阅将分别从0开始。+1 Ohhhh,是的,这似乎非常简单。我要试一试。这是一种非常糟糕的做法(调用“开始”),因为它打破了可观测模型,超出了众所周知的Rx实践(热观测和冷观测是不同的,IConnectableObservable
可以通过Connect
方法使用)。+1 Ohhhh,是的,这看起来非常简单。我要试一试。这是一种非常糟糕的做法(调用“开始”),因为它打破了可观察模型,超出了众所周知的Rx实践(热可观察和冷可观察是不同的,IConnectableObservable
可以通过Connect
方法获得)。对,对,好。我不确定我是否理解为什么这比其他地方描述的主题方法更好。你能扩展一下吗?不要调用resultStream.OnNext(i)代码>调用<代码>收益率i代码>-没有比这更多的了。您只是利用了一个事实,即可枚举的
和可观察的
是同一枚硬币的两面。Pi更容易作为可枚举项计算,所以我们这样做,然后转换为可观测项。如果热和冷对你没有影响的话,你可以完全忽略其他关于热和冷的东西。只需使用第一个方法,行Pi().ToObservable(Scheduler.ThreadPool)
将为您提供线程池上可观察的运行。对,对,好。我不确定我是否理解为什么这比其他地方描述的主题方法更好。你能扩展一下吗?不要调用resultStream.OnNext(i)代码>调用<代码>收益率i代码>-没有比这更多的了。您只是利用了一个事实,即可枚举的
和可观察的
是同一枚硬币的两面。Pi更容易作为可枚举项计算,所以我们这样做,然后转换为可观测项。如果热和冷对你没有影响的话,你可以完全忽略其他关于热和冷的东西。只需使用第一个方法,行Pi().ToObservable(Scheduler.ThreadPool)
将为您提供线程池上可观察的运行。