【问题标题】:Avoiding multiple calls in observable pipeline避免可观察管道中的多次调用
【发布时间】:2019-04-03 22:34:37
【问题描述】:

我正在尝试创建一个GetAndFetch 方法,该方法首先从缓存中返回数据,然后从 Web 服务中获取并返回数据,最后更新缓存。

akavache 中已经存在这样的函数,但是,它检索或存储的数据就像一个 blob。即,如果我对 rss 提要感兴趣,我只能在整个提要级别工作,而不是单个项目。我有兴趣创建一个将项目返回为IObservable<Item> 的版本。这样做的好处是新的Items 可以在service 返回后立即显示,而不是等待所有Itemss。

public IObservable<Item> GetAndFetch(IBlobCache cache, string feedUrl)
{
    // The basic idea is to first get the cached objects
    IObservable<HashSet<Item>> cacheBlobObject = cache.GetObject<HashSet<Item>>(feedUrl);

    // Then call the service   
    IObservable<Item> fetchObs = service.GetItems(feedUrl);

    // Consolidate the cache & the retrieved data and then update cache
    IObservable<Item> updateObs = fetchObs
                                      .ToArray()
                                      .MyFilter() // filter out duplicates between retried data and cache
                                      .SelectMany(arg =>
                                      {
                                          return cache.InsertObject(feedUrl, arg)
                                          .SelectMany(__ => Observable.Empty<Item>());
                                      });

    // Then make sure cache retrieval, fetching and update is done in order
    return cacheBlobObject.SelectMany(x => x.ToObservable())
                .Concat(fetchObs)
                .Concat(upadteObs);
}

我的方法的问题是Concat(upadteObs) 重新订阅fetchObs 并最终再次调用service.GetItems(feedUrl),这很浪费。

【问题讨论】:

    标签: system.reactive akavache


    【解决方案1】:

    听起来你需要.Publish(share =&gt; { ... }) 重载。

    试试这个:

    public IObservable<Item> GetAndFetch(IBlobCache cache, string feedUrl)
    {
        // The basic idea is to first get the cached objects
        IObservable<HashSet<Item>> cacheBlobObject = cache.GetObject<HashSet<Item>>(feedUrl);
    
        return
            service
                .GetItems(feedUrl)
                .Publish(fetchObs =>
                {
                    // Consolidate the cache & the retrieved data and then update cache
                    IObservable<Item> updateObs =
                        fetchObs
                            .ToArray()
                            .MyFilter() // filter out duplicates between retried data and cache
                            .SelectMany(arg =>
                                cache
                                    .InsertObject(feedUrl, arg)
                                    .SelectMany(__ => Observable.Empty<Item>()));
    
                    // Then make sure cache retrieval, fetching and update is done in order
                    return
                        cacheBlobObject
                            .SelectMany(x => x.ToObservable())
                            .Concat(fetchObs)
                            .Concat(updateObs);
                });
    }
    

    我担心Concat 电话 - 他们可能需要Merge

    此外,您对 service.GetItems 的调用似乎无论如何都在获取所有项目 - 它如何避免缓存中已经存在的项目?


    基于 cmets 的替代实现:

    public IObservable<Item> GetAndFetch(IBlobCache cache, string feedUrl)
    {
        return
        (
            from hs in cache.GetObject<HashSet<Item>>(feedUrl)
            let ids = new HashSet<string>(hs.Select(x => x.Id))
            select
                hs
                    .ToObservable()
                    .Merge(
                        service
                            .GetItems(feedUrl)
                            .Where(x => !ids.Contains(x.Id))
                            .Do(x => cache.InsertObject(feedUrl, new [] { x })))
        ).Merge();
    }
    

    【讨论】:

    • 我试过Merge,但没有奏效,我不确定原因。 service.GetItems 可能确实获得了已经在缓存中的相同项目。我依靠上面的层 (dynamic data) 过滤掉重复项。让我试试你的解决方案,然后回复你。
    • @resp78 - 我假设如果 service.GetItems 返回缓存中已经存在的项目,那么您正在使用缓存来始终拥有每个项目的相同实例,而不是减少项目的数量你拿?
    • 不是真的,我必须保持代码简短,有很多地方可以应用策略来使缓存中的项目过期,比如在返回时过滤掉(所以上面的层不要' t 看到它们),然后更新缓存。 MyFilter() 只能做我的 cmets 建议的事情。
    • @resp78 - 如果您仍然要获取所有值并且您不担心保持引用相同,那么缓存的意义何在?
    • 首先,快速响应用户,同时获取新数据。其次,如果网络出现故障,缓存将以离线模式为他们提供服务。
    猜你喜欢
    • 1970-01-01
    • 2020-02-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-06
    • 2018-04-13
    • 1970-01-01
    • 2015-11-05
    • 1970-01-01
    相关资源
    最近更新 更多