Rx Subscribe()回调问题

时间:2012-10-05 08:59:33

标签: c# system.reactive

我正在使用Reactive Extensions创建匿名Observable来执行Web请求,对其进行后处理并返回一些值。这种技术帮助我将价值获取的机制与使用这些价值的其他类别分开。 Web请求经常执行,因此有一个使用此技术构造和调用请求的计时器。我按如下方式构建了Observable:

Observable.FromAsyncPattern<WebResponse>(getRequest.BeginGetResponse, getRequest.EndGetResponse)

实际上,端点并不总是可用。在Web请求超时的情况下,永远不会调用Subscribe()方法中指定的回调。我正在使用Timeout() Rx扩展来处理这种情况。另外我正在对请求结果进行后处理。以下是我为解决此问题而实施的仿真代码:

var request = HttpWebRequest.Create("http://10.5.5.137/unreachable_endpoint");
var obs = Observable.FromAsyncPattern<WebResponse>(request.BeginGetResponse, request.EndGetResponse)();
var disposable = obs.Select(res => res.ContentLength).Timeout(TimeSpan.FromSeconds(2)).Subscribe(...)

然后我实现了处理Subscribe()方法的返回值以从Observable取消订阅回调委托。实际上我有一组三元组<IObservable obs, IDisposable disp, bool RequestComplete>Subscribe()方法回调设置RequestComplete = true并且随着时间的推移,如果不再需要Disposed,则所有一次性使用Disposed,即已经调用了回调。一切似乎都很好,但我注意到收藏品不断增长,我不知道为什么。

所以我实现了这种情况的模拟。这段代码没有处理部分 - 我用简单的请求计数器替换它:

public static class RequestCounter
{
    private static object syncRoot = new object();

    private static int count = 0;

    public static void Increment()
    {
        lock (syncRoot)
        {
            count++;
        }
    }

    public static void Decrement()
    {
        lock (syncRoot)
        {
            count--;
        }
    }

    public static int RequestCount
    {
        get { return count; }
    }
}

这是测试本身:

public void RunTest()
    {
        while (true)
        {
            var request = HttpWebRequest.Create("http://10.5.5.137/unreachable_endpoint");
            var obs = Observable.FromAsyncPattern<WebResponse>(request.BeginGetResponse, request.EndGetResponse)();
            RequestCounter.Increment();
            var disposable = obs.Select(res => res.ContentLength).Timeout(TimeSpan.FromSeconds(2)).Subscribe(
                res =>
                {
                    RequestCounter.Decrement();
                    Console.WriteLine("Pending requests count: {0}", RequestCounter.RequestCount);
                },
                ex =>
                {
                    RequestCounter.Decrement();
                    Console.WriteLine("Pending requests count: {0}", RequestCounter.RequestCount);
                },
                () =>
                {
                });
        }
    }

在Web请求计数器增加之前。请求超时后,它会递减。但请求计数器增长无限。你能解释一下我错过了什么吗?

1 个答案:

答案 0 :(得分:1)

对可观察序列的订阅是异步的。你的while循环尽可能快地继续前进。增量将超过延迟减量。

如果您在.NET 4.5中使用Rx v2.0,则可以使用await运行循环,并在上一个请求完成时继续执行以下迭代:

while (true)
{
    var obs = ...;

    RequestCounter.Increment();

    await obs.Select(...).Timeout(...);

    RequestCounter.Decrement();

    Console.WriteLine(...);
}

更大的问题是,如果请求完成,您为什么要尝试处理订阅?当序列到达终端状态(OnError,OnCompleted)时,Rx会自行清理,所以看起来你可以简单地将IDisposable对象放在地板上而不用担心它们。