订阅者缺少消息;这是 Rx 的错误还是我做错了?

Posted

技术标签:

【中文标题】订阅者缺少消息;这是 Rx 的错误还是我做错了?【英文标题】:Subscribers are missing messages; Is this a bug with Rx or its me doing it wrong? 【发布时间】:2013-09-14 21:40:39 【问题描述】:

我有一个带有以下构造函数的 Window WPF 应用程序

        numbers = Observable.Generate(DateTime.Now,
                                         time => true,
                                         time => DateTime.Now,
                                         time =>  return new     Random(DateTime.Now.Millisecond).NextDouble() * 99 + 2; ,
                                         time => TimeSpan.FromSeconds(1.0));


        numbers.ObserveOnDispatcher()
            .Subscribe(s => list1.Items.Add(s.ToString("##.00")));

        numbers.Where(n => n < 10).ObserveOnDispatcher().
            Subscribe(s => list2.Items.Add(s.ToString("##.00")));

现在这里是列表的屏幕截图 - 注意左侧列表中缺少 3.76...这种行为是间歇性的。

【问题讨论】:

“这是 Rx 的错误还是我做错了?” - 你给赔率吗? 我只是在问一个问题。赔率肯定对我不利。 图片似乎是一个损坏的链接。 我可以正常查看,您的浏览器/计算机可能会阻止来自您正在浏览的站点以外的站点的图像。这是网址s22.postimg.org/9paxw9rq9/Rx_bug.png 似乎是公司网络阻止了它。 【参考方案1】:

简短的回答是你做错了。 Rx 运行良好。

当您创建一个 observable 时,您是在创建一个随时间变化的值序列的定义,而不是随时间变化的实际值序列。这意味着,每当您拥有 observable 的订阅者时,您都会为每个订阅者创建 observable 的新实例。

因此,在您的情况下,您有两个运行此序列的实例:

var numbers =
    Observable
        .Generate(
            DateTime.Now,
            time => true,
            time => DateTime.Now,
            time => new Random(DateTime.Now.Millisecond)
                .NextDouble() * 99 + 2,
            time => TimeSpan.FromSeconds(1.0));

现在,由于您立即连续两次订阅此 observable,因此此 observable 的两个实例将尝试几乎同时生成值。所以DateTime.Now.Millisecond 的值在大多数情况下都是一样的,但现在总是一样。从new Random(x).NextDouble() 返回的值对于相同的x 是相同的,因此为什么大多数时候您从 observable 的两个实例中获得相同的值。只是当DateTime.Now.Millisecond 不同时,您会得到两个不同的值,并且订阅者似乎缺少值。


这是一个替代版本,应该可以按您最初的预期工作:

var rnd = new Random((int)DateTime.Now.Ticks);

var numbers =
    Observable
        .Generate(0, n => true, n => 0,
            n => rnd.NextDouble() * 99 + 2,
            n => TimeSpan.FromSeconds(1.0));

var publishedNumbers = numbers.Publish();

publishedNumbers
    .ObserveOnDispatcher()
    .Subscribe(s => list1.Items.Add(s.ToString("##.00")));

publishedNumbers
    .Where(n => n < 10)
    .ObserveOnDispatcher()
    .Subscribe(s => list2.Items.Add(s.ToString("##.00")));

publishedNumbers.Connect();

【讨论】:

很棒的观察。感谢分享。 你成就了我的一天...我将代码更改为使用 Second 而不是 Millisecond 现在我看不到这个问题了。 @fahadash - 将其更改为秒并不能解决问题,它只会降低 1000 倍的可能性。然后你就不能正确地产生随机数。你需要重构 observable 并且可能使用Publish 来共享 observable。 @fahadash - 我已经为您添加了一个替代解决方案,它的行为应该与您最初预期的一样。 ..我认为数字序列可以进一步简化为Observable.Interval(TimeSpan.FromSeconds(1.0)).Select(_=&gt;rnd.NextDouble() * 99 + 2)。我认为这更具表现力,即每秒从这个序列中投射一个随机数。

以上是关于订阅者缺少消息;这是 Rx 的错误还是我做错了?的主要内容,如果未能解决你的问题,请参考以下文章

是我做错了,还是在使用数组作为字段名时 CodeIgniter 表单验证库中存在错误?

为 OpenCart 上传数据库后,我收到此错误消息。我做错了啥? [复制]

Gmail API 中的 VacationSettings.endTime 转换为错误的日期 - 是错误还是我做错了啥?

我是 oracle 新手,但我在 oracle 的包中创建一个过程,我收到此错误消息 谁能看到我做错了啥?

JSON.parse,我做错了啥?

所有播放列表似乎都缺少订阅者