实现IObservable来计算Pi的数字

时间:2012-06-21 18:21:35

标签: asynchronous system.reactive pi

这是一个学术练习,我是Reactive Extensions的新手,并试图了解技术。我为自己设定了一个目标,即创建一个返回Pi的连续数字的IObservable(由于无关的原因,我恰好对Pi目前非常感兴趣)。 Reactive Extensions包含用于制作可观察对象的运算符,它们给出的指导是“几乎不需要创建自己的IObsevable”。但我看不出如何用现成的操作符和方法来做到这一点。让我进一步阐明一下。

我计划使用an algorithm,这将涉及为Arctan扩展泰勒系列。为了获得Pi的下一个数字,我将在该系列中扩展一些术语。

所以我需要异步进行系列扩展,偶尔会将下一个计算数字丢弃到IObserver。我显然不希望从头开始为每个新数字重新开始计算。

有没有办法使用RX的内置运算符来实现这种行为,或者我将不得不从头开始编写IObservable代码?什么策略表明自己?

2 个答案:

答案 0 :(得分:2)

对于这样的事情,最简单的方法是使用Subject。 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);
        }
    }
}

因此,在您的算法中,只要您想要生成下一个值,就可以在主题上调用OnNext

然后使用它,你只需要:

var piCalculator = new PiCalculator();
piCalculator.ResultStream.Subscribe(n => Console.WriteLine((n)));
piCalculator.Start();

答案 1 :(得分:1)

最简单的方法是创建Enumerable然后转换它:

IEnumerable<int> Pi()
{
    // algorithm here
    for (int i = 0; i < 1000; i++)
    {
        yield return i;
    }
}

用法(对于冷可观察,即每个新的'订阅'开始从头开始创建Pi):

var cold = Pi().ToObservable(Scheduler.ThreadPool);
cold.Take(5).Subscribe(Console.WriteLine);

如果你想让它hot(每个人共享相同的基础计算),你可以这样做:

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开始。