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

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

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

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

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

3 ответа

Решение

Определение

Мое (собственное) любимое определение:

Глюк - это временное несоответствие в наблюдаемом состоянии.

Определение из 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)
      • `consistencyCheck` запущен, `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);
});

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

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

Также смотрите 29-ю минуту разговора автора Натрия для другого ответа: http://youtu.be/gaG3tIb3Lbk.

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

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

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

А-> Б

А-> С

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

C не соответствует B.

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

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

Вот чрезвычайно короткий и теоретический пример фатальной ситуации с "сбоями" в C# 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, Так что с всегда должно быть 1,

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

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

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

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

Другие вопросы по тегам