ReactiveExtensions Observable FromAsync调用两次Function

时间:2012-11-26 21:49:14

标签: c# task system.reactive

好的,试着去理解Rx,有点迷失在这里。

现在不推荐使用FromAsyncPattern,所以我从here(使用Rx的Light up Task部分)中获取了示例,并且它可以工作,我只做了一些更改,而不是使用等待,只需等待observable和订阅...... ..

我不明白为什么称为SumSquareRoots函数的两倍?

 var res = Observable.FromAsync(ct => SumSquareRoots(x, ct))
                                      .Timeout(TimeSpan.FromSeconds(5));

            res.Subscribe(y => Console.WriteLine(y));

            res.Wait();


class Program
{
    static void Main(string[] args)
    {
        Samples();
    }

    static void Samples()
    {
        var x = 100000000;

        try
        {
            var res = Observable.FromAsync(ct => SumSquareRoots(x, ct))
                                      .Timeout(TimeSpan.FromSeconds(5));

            res.Subscribe(y => Console.WriteLine(y));

            res.Wait();
        }
        catch (TimeoutException)
        {
            Console.WriteLine("Timed out :-(");
        }
    }

    static Task<double> SumSquareRoots(long count, CancellationToken ct)
    {
        return Task.Run(() =>
        {
            var res = 0.0;
            Console.WriteLine("Why I'm called twice");
            for (long i = 0; i < count; i++)
            {
                res += Math.Sqrt(i);

                if (i % 10000 == 0 && ct.IsCancellationRequested)
                {
                    Console.WriteLine("Noticed cancellation!");
                    ct.ThrowIfCancellationRequested();
                }
            }

            return res;
        });
    }
}

1 个答案:

答案 0 :(得分:12)

这两次调用SumSquareRoots的原因是因为你订阅了两次:

// Subscribes to res
res.Subscribe(y => Console.WriteLine(y));

// Also Subscribes to res, since it *must* produce a result, even
// if that result is then discarded (i.e. Wait doesn't return IObservable)
res.Wait();

Subscribe是Rx的foreach - 就像你foreach IEnumerable两次一样,你最终可以完成2倍的工作,多个Subscribe s意味着多项工作。要撤消此操作,您可以使用不会丢弃结果的阻止调用:

Console.WriteLine(res.First());

或者,您可以使用Publish“冻结”结果并将其播放回&gt; 1个订阅者(有点像你在LINQ中使用ToArray的方式):

res = res.Publish();
res.Connect();

// Both subscriptions get the same result, SumSquareRoots is only called once
res.Subscribe(Console.WriteLine);
res.Wait();

您可以遵循的一般规则是,返回IObservable<T>Task<T>的任何Rx方法都将导致订阅(*)

* - 技术上不正确。但是如果你这样想的话,你的大脑会感觉更好。