Asynchronous 实现一个IObservable来计算Pi的位数

Asynchronous 实现一个IObservable来计算Pi的位数,asynchronous,system.reactive,pi,Asynchronous,System.reactive,Pi,这是一个学术性的练习,我对反应式扩展还不熟悉,并试图了解这项技术。我给自己设定了一个目标,就是制作一个IObservable,它返回Pi的连续数字(出于不相关的原因,我恰好对Pi非常感兴趣)。反应式扩展包含用于创建可观察对象的操作符,它们给出的指导是您应该“几乎不需要创建自己的IObsevable”。但我不知道如何使用现成的操作符和方法来实现这一点。让我再解释一下 我计划用它来扩展Arctan的泰勒级数。为了得到π的下一个数字,我将在序列中展开更多的项 因此,我需要异步进行序列扩展,偶尔向IOb

这是一个学术性的练习,我对反应式扩展还不熟悉,并试图了解这项技术。我给自己设定了一个目标,就是制作一个IObservable,它返回Pi的连续数字(出于不相关的原因,我恰好对Pi非常感兴趣)。反应式扩展包含用于创建可观察对象的操作符,它们给出的指导是您应该“几乎不需要创建自己的IObsevable”。但我不知道如何使用现成的操作符和方法来实现这一点。让我再解释一下

我计划用它来扩展Arctan的泰勒级数。为了得到π的下一个数字,我将在序列中展开更多的项

因此,我需要异步进行序列扩展,偶尔向IObserver抛出下一个计算数字。我显然不想重新开始计算每一个新的数字


有没有一种方法可以使用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)
将为您提供线程池上可观察的运行。