【问题标题】:merge performance in Functional Reactive programming (RX)合并函数响应式编程 (RX) 中的性能
【发布时间】:2015-09-07 19:50:28
【问题描述】:

在以下代码中:

http://jsfiddle.net/staltz/4gGgs/27/

var clickStream = Rx.Observable.fromEvent(button, 'click');

var multiClickStream = clickStream
    .buffer(function() { return clickStream.throttle(250); })
    .map(function(list) { return list.length; })
    .filter(function(x) { return x > 1; });

// Same as above, but detects single clicks
var singleClickStream = clickStream
    .buffer(function() { return clickStream.throttle(250); })
    .map(function(list) { return list.length; })
    .filter(function(x) { return x === 1; });

// Listen to both streams and render the text label accordingly
singleClickStream.subscribe(function (event) {
    document.querySelector('h2').textContent = 'click';
});
multiClickStream.subscribe(function (numclicks) {
    document.querySelector('h2').textContent = ''+numclicks+'x click';
});
Rx.Observable.merge(singleClickStream, multiClickStream)
    .throttle(1000)
    .subscribe(function (suggestion) {
        document.querySelector('h2').textContent = '';
    });

merge 之后,clickStream 序列将被迭代多少次? 我的意思是,它会是这样吗:

案例1

     for(numclicks : clickStream.length){
        if (numclicks === 1){ 
            document.querySelector('h2').textContent = 'click';
        }
     };
     for(numclicks : clickStream.length){
        if (numclicks > 1){ 
            document.querySelector('h2').textContent = ''+numclicks+'x click';
        }
     };

或者它会在内部,真正合并成这样的东西(伪代码):

案例2

    for(numclicks: clickStream.length){
        if (numclicks === 1){ 
            document.querySelector('h2').textContent = 'click';
        }else if(numclicks > 1){
            document.querySelector('h2').textContent = ''+numclicks+'x click';
        }
     }

我个人认为,合并只是按顺序将流应用于其参数(案例 1)。

附:我希望这样的事情有一些标准。但如果不是——我对 RxCpp 和 Sodium 的实现特别感兴趣。 我以 js 为例,因为更具交互性。

【问题讨论】:

    标签: reactive-programming


    【解决方案1】:

    fromEvent 返回一个 hot 源,因此所有订阅者共享相同的 for 循环迭代。

    忽略节流调用,结果类似于:

    for(numclicks: clickStream.length){
    
        // first subscription
        if (numclicks === 1){ 
            document.querySelector('h2').textContent = 'click';
        }
    
        // second subscription
        if(numclicks > 1){
            document.querySelector('h2').textContent = ''+numclicks+'x click';
        }
    
        // merged subscription
        if (numclicks === 0) {
            document.querySelector('h2').textContent = '';
        }
     }
    

    节流调用意味着循环的唯一点击流的主体实际上只是将点击事件推入两个缓冲区并重置三个节流操作符中的每一个中的计时器。 h2 在三个油门计时器之一触发时设置。由于计时器不共享,因此每个节流计时器都有一个单独的 for 循环,每个循环将 h2 设置为三个可能值之一:

    这种行为在所有 Rx 系列中都是相似的。

    特别是关于 rxcpp:

    rxcpp 缺少允许 observable 触发转换到新缓冲区的缓冲区重载。 rxcpp 尚未实施节流阀。 默认情况下,rxcpp 不是线程安全的(付费游戏),因此如果使用的节流计时器引入线程,则必须使用协调来显式添加线程安全。

    【讨论】:

    • 1)"rxcpp 缺少允许 observable 触发转换到新缓冲区的缓冲区重载" - 这是什么意思? 2)是否可以修改LINQ,使ifs变成ifelses/switch? :)
    • jsfiddle 中使用的缓冲区运算符采用一个返回可观察对象的函数。 rxcpp 还不支持这种形式的缓冲区操作符。
    • 我相信 if/else 是不可能的,因为每个块都是一个单独的函数。
    最近更新 更多