【问题标题】:Why do I NOT need Publish on this cold observable?为什么我不需要在这个冷的 observable 上发布?
【发布时间】:2011-11-12 19:59:19
【问题描述】:

既然我在这里感冒了Observable 并且我多次订阅“分组”,为什么我不需要在这里发布?当我运行它时,我本来希望它会带来不需要的结果,但令我惊讶的是,它可以在有和没有 Publish 的情况下工作。这是为什么呢?

var subject = new List<string>
    {                            
    "test",                        
    "test",                 
    "hallo",
    "test",
    "hallo"
    }.ToObservable();
subject
    .GroupBy(x => x)
    .SelectMany(grouped => grouped.Scan(0, (count, _) => ++count)
         .Zip(grouped, (count, chars) => new { Chars = chars, Count = count }))
    .Subscribe(result => Console.WriteLine("You typed {0} {1} times", 
         result.Chars, result.Count));

// I Would have expect that I need to use Publish like that
//subject
//   .GroupBy(x => x)
//   .SelectMany(grouped => grouped.Publish(sharedGroup => 
//       sharedGroup.Scan(0, (count, _) => ++count)
//       .Zip(sharedGroup, (count, chars) => 
//           new { Chars = chars, Count = count })))
//   .Subscribe(result => Console.WriteLine("You typed {0} {1} times", 
//       result.Chars, result.Count));

Console.ReadLine();

编辑

正如 Paul 所注意到的,因为我们订阅了两次底层的冷可观察对象,所以我们应该检查两次序列。但是,我没有运气使这种效果可见。我试图插入调试行,但例如这只会打印一次“执行”。

var subject = new List<Func<string>>
{                            
() =>
    {
        Console.WriteLine("performing");
        return "test";
    },                        
() => "test",                 
() => "hallo",
() => "test",
() => "hallo"
}.ToObservable();


subject
    .Select(x => x())
    .GroupBy(x => x)
    .SelectMany(grouped => grouped.Scan(0, (count, _) => ++count)
            .Zip(grouped, (count, chars) => new { Chars = chars, Count = count }))
    .Subscribe(result => Console.WriteLine("You typed {0} {1} times",
            result.Chars, result.Count));

我想知道我们是否可以使我们正在处理一个冷的 observable 并且没有使用Publish() 的效果可见。在另一个步骤中,我想看看Publish()(见上文)如何使效果消失。

编辑 2

正如 Paul 所建议的,我创建了一个自定义 IObservable&lt;string&gt; 用于调试目的。但是,如果您在它的 Subscribe() 方法中设置断点,您会注意到它只会被命中一次

class Program
{
    static void Main(string[] args)
    {
        var subject = new MyObservable();

        subject
            .GroupBy(x => x)
            .SelectMany(grouped => grouped.Scan(0, (count, _) => ++count)
                 .Zip(grouped, (count, chars) => new { Chars = chars, Count = count }))
            .Subscribe(result => Console.WriteLine("You typed {0} {1} times",
                 result.Chars, result.Count));

       Console.ReadLine();
   }
}

class MyObservable : IObservable<string>
{
    public IDisposable Subscribe(IObserver<string> observer)
    {
        observer.OnNext("test");
        observer.OnNext("test");
        observer.OnNext("hallo");
        observer.OnNext("test");
        observer.OnNext("hallo");
        return Disposable.Empty;
    }
}

所以对我来说,这个问题仍然悬而未决。为什么我在这个寒冷的Observable 上不需要Publish

【问题讨论】:

    标签: c# system.reactive reactive-programming observable


    【解决方案1】:

    您只使用一次基于列表的源,因此您不会看到重复的订阅效果。回答您的问题的关键是以下观察:

    一个 IGroupedObservable 对象本身流出 GroupBy 是一个伪装的主题。

    在内部,GroupBy 保存一个 Dictionary>。每当有消息进来时,它都会使用相应的键发送到主题中。您订阅了两次分组对象,这是安全的,因为主体将生产者与消费者分离。

    【讨论】:

    • 棒极了巴特!我认为这有点接近我在对保罗回答的最后评论中所说的。谢谢你说清楚!顺便说一句,真棒让你终于在 SO 上。希望很快在推特上见到你 :) 喜欢你的视频。摇滚吧!
    【解决方案2】:

    在 Zip 中重复使用“分组”意味着您实际上对每个分组进行了两次 - 但是,由于您的来源是冷的,它仍然有效。这有意义吗?

    【讨论】:

    • 我们能否让“分组两次”的效果以某种方式可见?我尝试插入 Do() 以查看它是否多次分组但没有运气。另外,如果它真的表现得像那样,为什么扫描不重复计数?问题是,我们能否使任何效果可见,以显示该计算在热或冷可观察对象上的表现如何不同?然后,我们能否进一步展示如何使用 Publish 避免内部重复(如果存在)?
    • 想一想 Zip 操作符在其实现中将要做什么——它将订阅 SelectMany 结果(in.GroupBy.Scan),它还将订阅 'grouped'(在。通过...分组)。同一输入有 2 个订阅,因此最终会得到两个“输入”副本(因为它很冷)。
    • 您能否编辑您的答案以在代码中向我展示如何使此效果可见?就像插入 Do()'s、触发 GUID 或 s.th。我请求你这样做。我真的很担心。我发誓,我把这个答案作为公认的答案,然后停止打扰你;-)
    • 创建一个自定义 IObservable 来包装你的数组,然后在订阅上设置断点:)
    • 做到了。这只是一个 Subscribe() 调用(请参阅更新的问题)。实际上是 GroupBy() 运算符负责使冷的 Observable 变热,这就是为什么即使您的源实际上是冷的,您也可以多次订阅 GroupBy 运算符的结果?这有意义吗?
    猜你喜欢
    • 2010-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-29
    • 2017-06-22
    • 2017-08-26
    • 1970-01-01
    相关资源
    最近更新 更多