Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Олег Докука — Реактивный Хардкор

3fc5b5eb32bd3b48d7810fd67b37f9a1?s=47 Moscow JUG
December 13, 2018

Олег Докука — Реактивный Хардкор

Разрабатываете свою библиотеку? Решили поддерживать Reactive-Streams specification? Хотите понять, что творится под капотом у RxJava 2 или Reactor 3? Либо же вы любитель хардкора? Тогда этот доклад для вас!

Во время доклада мы затронем причины создания спецификации Reactive-Streams и сложность в работе с ней. Как первый шаг — создадим наивную реализацию интерфейсов, посмотрим, где же напортачили, как протестить корректность. Шаг за шагом мы доберемся до правды и пройдем через все испытания в разработке операторов. В результате вынесем лучшие практики в реализации таких зверей, разберем, что, как и зачем, на пальцах и убедимся, что именно так всё и работает в модерных библиотеках, таких как RxJava 2 и Reactor 3.

После этого доклада у вас будет понимание того, как создать и протестировать свой оператор. Вдобавок у вас будет более четкое понимание того, как устроены реактивные библиотеки. Также вы увидите сложности конкуретной разработки и поймете, как с этим жить.

3fc5b5eb32bd3b48d7810fd67b37f9a1?s=128

Moscow JUG

December 13, 2018
Tweet

Transcript

  1. / by Oleh Dokuka Реактивный Хардкор

  2. / Oleh Dokuka 2 Реактивный Хардкор Для кого? / Вы

    психанули, и реализовываете свою реактивную библиотеку / Вам хочется понять как оно работает / Вы просто любите хардкора
  3. Oleh Dokuka Реактивный Хардкор / Oleh Dokuka 3 3

  4. None
  5. / Oleh Dokuka 5 Реактивный Хардкор План / Реактивная Спека

    / Имплементим хардкор / Итожим
  6. / Oleh Dokuka Reactive-Streams Реактивный Хардкор 6

  7. / Oleh Dokuka Subscription Publisher<T> Реактивный Хардкор 7 Subscriber<T> subscribe()

  8. / Oleh Dokuka Publisher<T> Реактивный Хардкор 8 request(5) onNext() Subscriber<T>

    Subscription
  9. / Oleh Dokuka Реактивный Хардкор 9 public interface Publisher<T> {

    private final T[] source; public ArrayPublisher(T[] source) { this.source = source; } @Override public void subscribe(Subscriber<? super T> subscriber);{ for (int i = 0; i < source.length; i++) { subscriber.onNext(source[i]); } } } public class ArrayPublisher<T> implements Publisher<T> { private final T[] source; public ArrayPublisher(T[] source) { this.source = source; } @Override public void subscribe(Subscriber<? super T> subscriber) { for (int i = 0; i < source.length; i++) { subscriber.onNext(source[i]); } } } public class ArrayPublisher<T> implements Publisher<T> { private final T[] source; public ArrayPublisher(T[] source) { this.source = source; } @Override public void subscribe(Subscriber<? super T> subscriber) { for (int i = 0; i < source.length; i++) { subscriber.onNext(source[i]); } } }
  10. / Oleh Dokuka 10 Реактивный Хардкор Потому что спека 100500

    41 https://github.com/reactive-streams/reactive-streams-jvm/blob/v1.0.2/README.md#specification
  11. / Oleh Dokuka 11 Реактивный Хардкор Все по порядку /

    onSubscribe() 1 / onNext() 0..N / onError | onComplete() 1
  12. / Oleh Dokuka 12 Реактивный Хардкор Сколько request() столько и

    onNext() request(5) { onNext(a) onNext(b) onNext(c) onNext(d) onNext(e) }
  13. / Oleh Dokuka 13 Реактивный Хардкор Не onNext(null) Subscriber-у своему

  14. / Oleh Dokuka 14 Реактивный Хардкор Не убей себя рекурсией

    onNext(a) { request(1) { onNext(b) { request(1) { } } } }
  15. / Oleh Dokuka 15 Если cancel() значит не надо Реактивный

    Хардкор
  16. / Oleh Dokuka Демо 1 по простому 16 Реактивный Хардкор

  17. / Oleh Dokuka Publisher<T> Реактивный Хардкор 17 request(5) onNext() Subscription

    Subscriber<T>
  18. / Oleh Dokuka 18 Work in Progress (WIP) Title Text

    Title Text Предотвращаете бесконечную рекурсию: request(onNext(request(onNext…))))
  19. / Oleh Dokuka 19 Реактивный Хардкор TCK / Проверяет все

    правила из коробки
  20. / Oleh Dokuka 20 Реактивный Хардкор Итожим / Работает /

    Тесты проходят / Немного сложно
  21. / Oleh Dokuka Многопоточность Реактивный Хардкор 21

  22. / Oleh Dokuka 22 Реактивный Хардкор Потоко - безопасный /

    onNext() / onComplete() / onError()
  23. / Oleh Dokuka 23 request() - Non-blocking Реактивный Хардкор

  24. / Oleh Dokuka 24 cancel() - Non-blocking Реактивный Хардкор

  25. / Oleh Dokuka Демо 2 многопоточней Реактивный Хардкор 25

  26. / Oleh Dokuka Реактивный Хардкор 26 AtomicLong requested = new

    AtomicLong(); @Override public void request(long n) { long initialRequested = requested.getAndAdd(n); if (initialRequested > 0) { return; } for (...) { ... } ... requested.addAndGet(-sent); } 0 0 0
  27. / Oleh Dokuka Реактивный Хардкор 27 AtomicLong requested = new

    AtomicLong(); @Override public void request(long n) { long initialRequested = requested.getAndAdd(n); if (initialRequested > 0) { return; } for (...) { ... } ... requested.addAndGet(-sent); } 0 0 0
  28. / Oleh Dokuka Реактивный Хардкор 28 5 0 AtomicLong requested

    = new AtomicLong(); @Override public void request(long n) { long initialRequested = requested.getAndAdd(n); if (initialRequested > 0) { return; } for (...) { ... } ... requested.addAndGet(-sent); } 0
  29. / Oleh Dokuka Реактивный Хардкор 29 AtomicLong requested = new

    AtomicLong(); @Override public void request(long n) { long initialRequested = requested.getAndAdd(n); if (initialRequested > 0) { return; } for (...) { ... } ... requested.addAndGet(-sent); } 5 0 0
  30. / Oleh Dokuka Реактивный Хардкор 30 AtomicLong requested = new

    AtomicLong(); @Override public void request(long n) { long initialRequested = requested.getAndAdd(n); if (initialRequested > 0) { return; } for (...) { ... } ... requested.addAndGet(-sent); } 5 0 0
  31. / Oleh Dokuka Реактивный Хардкор 31 AtomicLong requested = new

    AtomicLong(); @Override public void request(long n) { long initialRequested = requested.getAndAdd(n); if (initialRequested > 0) { return; } for (...) { ... } ... requested.addAndGet(-sent); } 5 0 5
  32. / Oleh Dokuka Реактивный Хардкор 32 AtomicLong requested = new

    AtomicLong(); @Override public void request(long n) { long initialRequested = requested.getAndAdd(n); if (initialRequested > 0) { return; } for (...) { ... } ... requested.addAndGet(-sent); } 0 0 5
  33. / Oleh Dokuka Реактивный Хардкор 33 AtomicLong requested = new

    AtomicLong(); @Override public void request(long n) { long initialRequested = requested.getAndAdd(n); if (initialRequested > 0) { return; } for (...) { ... } ... requested.addAndGet(-sent); } 0 0 0
  34. / Oleh Dokuka Реактивный Хардкор 34 AtomicLong requested = new

    AtomicLong(); @Override public void request(long n) { long initialRequested = requested.getAndAdd(n); if (initialRequested > 0) { return; } for (...) { ... } ... requested.addAndGet(-sent); } 5 0 0
  35. / Oleh Dokuka Реактивный Хардкор 35 AtomicLong requested = new

    AtomicLong(); @Override public void request(long n) { long initialRequested = requested.getAndAdd(n); if (initialRequested > 0) { return; } for (...) { ... } ... requested.addAndGet(-sent); } 5 0 1
  36. / Oleh Dokuka Реактивный Хардкор 36 AtomicLong requested = new

    AtomicLong(); @Override public void request(long n) { long initialRequested = requested.getAndAdd(n); if (initialRequested > 0) { return; } for (...) { ... } ... requested.addAndGet(-sent); } 5 0 5
  37. / Oleh Dokuka Реактивный Хардкор 37 AtomicLong requested = new

    AtomicLong(); @Override public void request(long n) { long initialRequested = requested.getAndAdd(n); if (initialRequested > 0) { return; } for (...) { ... } ... requested.addAndGet(-sent); } 10 5 5
  38. / Oleh Dokuka Реактивный Хардкор 38 AtomicLong requested = new

    AtomicLong(); @Override public void request(long n) { long initialRequested = requested.getAndAdd(n); if (initialRequested > 0) { return; } for (...) { ... } ... requested.addAndGet(-sent); } 5 5 5
  39. / Oleh Dokuka Реактивный Хардкор 39 AtomicLong requested = new

    AtomicLong(); @Override public void request(long n) { long initialRequested = requested.getAndAdd(n); if (initialRequested > 0) { return; } for (...) { ... } ... requested.addAndGet(-sent); } 5 5 0
  40. / Oleh Dokuka 40 AtomicLong requested = new AtomicLong(); @Override

    public void request(long n) { long initialRequested = requested.getAndAdd(n); if (initialRequested > 0) { return; } for (...) { ... } ... requested.addAndGet(-sent); } 5 5 0 Реактивный Хардкор
  41. / Oleh Dokuka 41 java.util.concurrent.atomic Реактивный Хардкор для эффективного, не-блокирующего

    взаимодействия с памятью
  42. / Oleh Dokuka 42 WIP + Infinite Loop Реактивный Хардкор

    Для того что бы WIP работал хорошо во время многопоточной гонки
  43. / Oleh Dokuka 43 Собственный getAndAdd Реактивный Хардкор для предотвращения

    Long.MAX_VALUE + 1
  44. / Oleh Dokuka 44 Реактивный Хардкор Итожим / Ну, кажись

    работает / Код - ужас
  45. / Oleh Dokuka Оптимизируем Реактивный Хардкор 45

  46. / Oleh Dokuka 46 Реактивный Хардкор Оптимизируем / Доступ к

    переменным / Количество атомарных оп-ий / Количество созданных объектов / Путь выполнения
  47. / Oleh Dokuka 47 Реактивный Хардкор Попросили Long.MAX_VALUE - отсылай

    сколько хочешь
  48. / Oleh Dokuka Демо 3 оптимизируем Реактивный Хардкор 48

  49. / Oleh Dokuka 49 Всегда JMH Реактивный Хардкор

  50. / Oleh Dokuka 50 Все в стеке Реактивный Хардкор Можем

    выиграть 1 инструкцию
  51. / Oleh Dokuka 51 Внимательно изучаем спеку Реактивный Хардкор Спека

    дает подсказки для оптимизаций
  52. / Oleh Dokuka 52 Реактивный Хардкор Итожим / Оптимизация успешна

    / Наш код == Reactor код
  53. / Oleh Dokuka 53 Реактивный Хардкор Паттерны / WIP -

    работа в прогрессе / бесконечный цикл / fastPath / slowPath / AtomicXXXFieldUpdater
  54. / Oleh Dokuka 54 Реактивный Хардкор Итог / Ничего страшного

    нету / Все для скорости и низкой задержки / TCK - помогает, но кое-что сами / Мойте руки после говно-кода
  55. /oleh.dokuka /OlegDokuka /OlehDokuka Вопросы и Спасибо! 2018 Окт 20 Презентация

    Код