Терминология: что такое "глюк" в функциональном реактивном программировании/RX?

Что такое определение "сбой" в контексте функционального реактивного программирования?

Я знаю, что в некоторых FRP-системах "глюки" могут возникать, в то время как в других нет. Например, RX не сбой, в то время как ReactFX не работает с ошибками [1].

Может ли кто-нибудь дать очень простой пример, демонстрирующий, как и когда могут возникнуть сбои при использовании RX и показать на том же примере, как и почему соответствующее решение ReactFX является сбойным.

Спасибо за чтение.

Ответ 1

Определение

Мое любимое определение:

Сбой - временная несогласованность в наблюдаемом состоянии.

Определение Scala.Rx:

В контексте FRP сбой - временная несогласованность графика данных. Из-за того, что обновления не происходят мгновенно, но вместо этого требуется время для вычисления, значения в системе FRP могут временно не синхронизироваться в процессе обновления. Кроме того, в зависимости от характера FRP-системы возможно, что узлы будут обновляться более одного раза при распространении.

Пример

Рассмотрим целочисленные переменные a, b. Определите sum и prod такие, что sum := a + b,
prod := a * b.

Перепишите этот пример в JavaFX:

IntegerProperty a = new SimpleIntegerProperty();
IntegerProperty b = new SimpleIntegerProperty();
NumberBinding sum = a.add(b);
NumberBinding prod = a.multiply(b);

Теперь напишите небольшую проверку последовательности:

InvalidationListener consistencyCheck = obs -> {
    assert sum.intValue() == a.get() + b.get();
    assert prod.intValue() == a.get() * b.get();
};

sum.addListener(consistencyCheck);
prod.addListener(consistencyCheck);

a.set(1);
b.set(2);

Этот код выходит из строя с ошибкой утверждения в последней строке, потому что:

  • b обновляется (до 2)
    • sum обновляется (до 3)
      • `constencyCheck` запускается` a == 1`, `b == 2`, но` prod == 0`, потому что `prod` еще не обновлен

Это глюк; prod временно не соответствует a и b.

Устранение сглаживания с использованием ReactFX

Прежде всего, обратите внимание, что ReactFX не "сбой" из коробки, но он дает вам инструменты для устранения сбоев. Если вы не предпримете каких-либо сознательных усилий для их использования, ReactFX не будет более сбойным, чем RX (например, rxJava).

Методы устранения сбоев в ReactFX основаны на том, что распространение событий является синхронным. С другой стороны, распространение событий в RX всегда асинхронно, поэтому эти методы не могут быть реализованы в RX-системе.

В приведенном выше примере мы хотим отложить уведомления о прослушивании до тех пор, пока не будут обновлены как теги sum, так и prod. Вот как это сделать с помощью ReactFX:

import org.reactfx.Guardian;
import org.reactfx.inhibeans.binding.Binding;

IntegerProperty a = new SimpleIntegerProperty();
IntegerProperty b = new SimpleIntegerProperty();
Binding<Number> sum = Binding.wrap(a.add(b)); // Binding imported from ReactFX
Binding<Number> prod = Binding.wrap(a.multiply(b)); // Binding imported from ReactFX

InvalidationListener consistencyCheck = obs -> {
    assert sum.getValue().intValue() == a.get() + b.get();
    assert prod.getValue().intValue() == a.get() * b.get();
};

sum.addListener(consistencyCheck);
prod.addListener(consistencyCheck);

// defer sum and prod listeners until the end of the block
Guardian.combine(sum, prod).guardWhile(() -> {
    a.set(1);
    b.set(2);
});

Ответ 2

Вот очень короткий и теоретический пример фатальной "сбой" ситуации в С# RX

var t = Observable
        .Interval(TimeSpan.FromSeconds(1))
        .Publish()
        .RefCount();

var s = t.CombineLatest(t, (t1,t2) => 1/(1-(t1-t2));

Так как t1 и t2 оба представляют последнее значение горячего наблюдаемого t, предполагается, что t1-t2 всегда будет 0. Поэтому s всегда должно быть 1.

Но при подписке на s мы действительно получаем 1 как первое наблюдаемое значение, но затем получаем деление на ноль исключение. В RxJS мы получили бы NaN.

Причина проста: a.CombineLatest(b, f) будет реагировать, когда либо a, либо b выдает значение, комбинируя это новое значение и последнее наблюдаемое значение другого наблюдаемого. Это по дизайну, но, по моему опыту, люди, использующие RX, иногда считают, что это глюки, особенно когда они поступают из других библиотек FRP, которые имеют другое понятие "последние".

Это, конечно, надуманный пример, просто означающий иллюстрацию неправильного представления о CombineLatest.

Может быть, CombineLatest должен был называться WhenAny, как в библиотеке ReactiveUI, это прояснит оперативную семантику?

Ответ 3

Короткий ответ: glitch = inonconsistent/незаконное/бессмысленное состояние.

Вот ссылка: https://social.msdn.microsoft.com/Forums/en-US/bc2c4b71-c97b-428e-ad71-324055a3cd03/another-discussion-on-glitches-and-rx?forum=rx

Кроме того, см. 29-я минута интервью автора Sodium для другого ответа: http://youtu.be/gaG3tIb3Lbk.

И соответствующий ответ SOF: как избежать глюков в Rx

Итак, вот мое понимание того, что глюк основан на ответе Томаса.

Существует граф потока данных с тремя узлами: A, B, C

А- > В

А- > С

В этом простом примере сбой происходит, если я изменяю A и что вызывает изменение B, но C еще не обновлен. Это сбой.

C не согласуется с B.

Скажем B = 2 * A, C = 2 * A.

Тогда, если B не равно C, то это сбой.