简体   繁体   English

反应性扩展缓冲订阅

[英]Reactive Extensions buffering subscriptions

I am fairly new to Rx and am having trouble finding a solution to my problem. 我对Rx相当陌生,无法找到解决我问题的方法。 I am using Rx to commence a download through a client library. 我正在使用Rx通过客户端库开始下载。 Currently it looks like: 当前看起来像:

private void DownloadStuff(string descriptor, Action<Stuff> stuffAction)
{
    this.stuffDownloader.GetStuffObservable(descriptor).Subscribe(x => stuffAction(x))
}

Where stuffDownloader is a wrapper around download logic defined in the client library. 其中,stuffDownloader是围绕客户端库中定义的下载逻辑的包装器。 But I encountered a problem where I call DownloadStuff too much, causing many downloads, and overwhelming the system. 但是我遇到了一个问题,我称它为DownloadStuff太多,导致许多下载,并使系统不堪重负。 Now what I would like to do is 现在我想做的是

private void DownloadStuff(string descriptor, Action<Stuff> stuffAction)
{
    this.stuffDownloader.GetStuffObservable(descriptor)
        .SlowSubscribe(TimeSpan.FromMilliSeconds(50))
        .Subscribe(x => stuffAction(x))
}

Where SlowSubscribe is some combination of Rx actions to only subscribe on some interval. 其中SlowSubscribe是Rx动作的某种组合,只能在某个时间间隔进行订阅。

Normally I would just put these DownloadStuff calls on a queue and pull them off on an interval, but I've been trying to do more through Rx lately. 通常,我只是将这些DownloadStuff调用放在队列中,并在一定间隔内将其拉出,但是最近我一直在尝试通过Rx做更多的事情。 Three solutions occur to me: 我想到了三种解决方案:

  1. This functionality exists and can be done all on the subscription side. 此功能存在,可以在订阅端全部完成。
  2. This is possible but the infrastructure of the downloader is incorrect and should change (ie stuffDownloader needs to behave differently) 这是可能的,但是下载器的基础结构不正确并且应该更改(即,stuffDownloader需要采取不同的行为)
  3. This shouldn't be done with Rx, do it another way. 这不应该用Rx完成,而是用另一种方式。

It occurs to me #2 is possible by passing an IObservable of descriptors to the client library and somehow slowing how the descriptors get onto the Observable. 在我看来,第二种可能是通过将IObservable描述符传递给客户端库,并以某种方式减慢了描述符进入Observable的速度。

You could in theory use Rx to treat your requests as events. 从理论上讲,您可以使用Rx将您的请求视为事件。 This way you could leverage the serializing nature of Rx to queue up downloads. 这样,您可以利用Rx的序列化性质来排队下载。

I would think that you network layer (or stuffDownloader) would do this for you, but if you want to join me for a hack....this is what I have come up with (Yeehaw!!) 我认为您的网络层(或stuffDownloader)会为您完成此操作,但是如果您想加入我的行列,...这就是我想出的(Yeehaw!)

1. Dont pass an Action, use Rx!! 1.不要通过动作,使用Rx !! You are basically losing the error handling here and setting yourself up for weird unhandled exceptions. 您基本上在这里失去了错误处理,并为怪异的未处理异常做好了准备。

private void DownloadStuff(string descriptor, Action<Stuff> stuffAction)

becomes 变成

private IObservable<Stuff> DownloadStuff(string descriptor)

2. Now we just have one method calling another. 2.现在,我们只有一个方法调用另一个方法。 Seems pointless. 似乎毫无意义。 Throw away the abstraction. 扔掉抽象。

3. Fix the underlying. 3.修复基础。 To me the stuffDownloader is not doing it's job. 对我而言,stuffDownloader并没有完成它的工作。 Update the interface to take an IScheduler. 更新接口以使用IScheduler。 Now you can pass it a dedicated EventLoopScheduler to enforce the serialization of the work 现在,您可以将专用的EventLoopScheduler传递给它,以强制执行工作的序列化

public IObservable<Stuff> GetStuffObservable(string descriptor, IScheduler scheduler)

4. Fix the implementation? 4.修复执行情况? As you want to serialize your requests (hmmmm....) you can just make the call synchronous. 当您要序列化您的请求时(hmmmm ....),您可以使调用同步。

private Stuff GetSync(string description)
{
    var request = (HttpWebRequest)WebRequest.Create("http://se300328:90/");
    var response =request.GetResponse();
    var stuff = MapToStuff(response);
    return stuff;
}

Now you just call that in you other method 现在您只需用其他方法调用它

public IObservable<Stuff> GetStuffObservable(string descriptor, ISchedulerLongRunning scheduler)
{
    return Observable.Create<Stuff>(o=>
        {
            try
            {
                var stuff = GetStuff(description);
                o.OnNext(stuff);
                o.OnCompleted();
            }
            catch(Exception ex)
            {
                o.OnError(ex);
            }
            return Disposable.Empty(); //If you want to be sync, you cant cancel!
        })
        .SubscribeOn(scheduler);
}

However, having done all of this, I am sure this is not what you really want. 但是,完成所有这些操作后,我确定这不是您真正想要的。 I would expect that there is a problem somewhere else in the system. 我希望系统中其他地方存在问题。

Another alternative is to consider using the Merge operator and it's max concurent feature? 另一个选择是考虑使用Merge运算符及其最大并发功能吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM