Слайды вебинара http://www.ptsecurity.ru/lab/webinars/#42235 :
"Каковы формальные признаки уязвимого и защищенного кода? Что такое уязвимость? Как разглядеть в коде уязвимость для атак, принадлежащих неизвестному классу? Чем уязвимости бизнес-логики отличаются от «традиционных» уязвимостей? Мы ответим на эти вопросы на вебинаре, посвященном теоретическому минимуму предметной области Application Security и практическому применению этих знаний в задачах анализа защищенности и при разработке защищенного кода"
Java SE 8 has brought lambdas, default methods, type annotations, compact profiles, etc. As a result, the Java SE platform specification was changed to reflect new features.
The session shows how the new Java 8 features have been implemented in Excelsior JET JVM, written from scratch, very different from the Oracle HotSpot JVM, but compatible with the Java SE specification.
As a result, an attendee will refresh his/her memory regarding new Java 8 features, will learn how they affected the JVM specification, how the lambda expressions are translated into Java bytecode and how they can be optimized at the JVM level.
Верификация Java байткода: когда, как, а может отключить?Nikita Lipsky
Сегодня Java разработчики все чаще используют библиотеки для порождения Java байт-кода в рантайме. Делается это для эффективной реализации различных трюков, которые сложно или невозможно выразить на языке Javа. Когда используется Java, компилятор javac гарантирует, что на выходе получится корректный Java байт-код. Но, спускаясь на уровень непосредственно байт-кода, часто нужно самостоятельно следить за его корректностью. Иначе при загрузке порожденных классов на выходе будет j.l.VerifyError, потому что JVM посредством верификатора Java байт-кода строго следит за корректностью байт-кода, который она загружает. Таким образом, порождая байт-код, недостаточно просто знать семантику байт-кодных инструкций — нужно также знать, как работает Java byte-code верификатор, какой байт-код он считает корректным, а какой нет.
В этом докладе мы разберемся, какую миссию в JVM несет верификатор байт-кода, когда и как он работает, может ли повлиять на производительность вашего приложения и почему опасно его отключать.
Слайды вебинара http://www.ptsecurity.ru/lab/webinars/#42235 :
"Каковы формальные признаки уязвимого и защищенного кода? Что такое уязвимость? Как разглядеть в коде уязвимость для атак, принадлежащих неизвестному классу? Чем уязвимости бизнес-логики отличаются от «традиционных» уязвимостей? Мы ответим на эти вопросы на вебинаре, посвященном теоретическому минимуму предметной области Application Security и практическому применению этих знаний в задачах анализа защищенности и при разработке защищенного кода"
Java SE 8 has brought lambdas, default methods, type annotations, compact profiles, etc. As a result, the Java SE platform specification was changed to reflect new features.
The session shows how the new Java 8 features have been implemented in Excelsior JET JVM, written from scratch, very different from the Oracle HotSpot JVM, but compatible with the Java SE specification.
As a result, an attendee will refresh his/her memory regarding new Java 8 features, will learn how they affected the JVM specification, how the lambda expressions are translated into Java bytecode and how they can be optimized at the JVM level.
Верификация Java байткода: когда, как, а может отключить?Nikita Lipsky
Сегодня Java разработчики все чаще используют библиотеки для порождения Java байт-кода в рантайме. Делается это для эффективной реализации различных трюков, которые сложно или невозможно выразить на языке Javа. Когда используется Java, компилятор javac гарантирует, что на выходе получится корректный Java байт-код. Но, спускаясь на уровень непосредственно байт-кода, часто нужно самостоятельно следить за его корректностью. Иначе при загрузке порожденных классов на выходе будет j.l.VerifyError, потому что JVM посредством верификатора Java байт-кода строго следит за корректностью байт-кода, который она загружает. Таким образом, порождая байт-код, недостаточно просто знать семантику байт-кодных инструкций — нужно также знать, как работает Java byte-code верификатор, какой байт-код он считает корректным, а какой нет.
В этом докладе мы разберемся, какую миссию в JVM несет верификатор байт-кода, когда и как он работает, может ли повлиять на производительность вашего приложения и почему опасно его отключать.
PG Day'14 Russia, PostgreSQL: архитектура, настройка и оптимизация, Илья Косм...pgdayrussia
Доклад был представлен на официальной российской конференции PG Day'14 Russia, посвященной вопросам разработки и эксплуатации PostgreSQL.
Основные принципы устройства PostgreSQL, ключевые принципы правильного конфигурирования и подходы к оптимизации под высокие нагрузки — обо всем этом Илья поведает на специальном мастер-классе, посвященном "внутренностям" СУБД. Курс предназначен как для опытных профессионалов, так и для "молодых бойцов". Полученные в ходе прослушивания семинара знания пригодятся не только на практике. Они также призваны увеличить эффективность восприятия слушателями и, как следствие, полезность докладов, запланированных на второй день конференции.
Как база работает с памятью и файловой системой? Для чего предназначено версионирование? Что такое транзакции, как они устроены и почему полезны? Как строятся индексы и что происходит с запросом во время его выполнения? Что такое репликация и почему ее нельзя применять для backup/recovery? На все эти вопросы, и не только, ответит Илья.
Разобравшись с основами и "матчастью", мы перейдем к самому интересному: "тюнингу" базы в нагруженных системах, начиная с классического "Почему у меня тормозит запрос?" и заканчивая кручением "гаек" системных процессов "посгреса" под объемы данных и транзакционные нагрузки, соизмеримые с "big data".
Консервативный Backend на Node.js / Дмитрий Ляпин (Recrumatic)Ontico
РИТ++ 2017, Backend Conf
Зал Кейптаун, 5 июня, 14:00
Тезисы:
http://backendconf.ru/2017/abstracts/2510.html
Я расскажу об опыте разработки REST API сервиса одной рекрутинговой платформы. Стремясь найти простое и масштабируемое решение, мы выбираем PostgreSQL и Node.js, а вместо сессий используем JWT-токены. Избегая ORM, мы пишем большие и сложные, но эффективные SQL-запросы. На помощь приходят SQL-представления, триггеры и небольшая собственная JS-библиотека.
...
Ангелы и демоны многопоточного программирования / Алексей Федоров (Одноклассн...Ontico
Современные процессоры имеют на борту по нескольку вычислительных ядер, позволяющих запускать задачи на них параллельно. И, казалось бы, вот оно — счастье: бей большие задачи на куски, запускай эти куски параллельно на разных ядрах и радуйся.
Но не все так просто. Для того чтобы одновременный доступ к общим данным выполнялся корректно, современные системы используют разные примитивы синхронизации. В основе одних лежат блокировки (locks), в основе других — операции типа сравнение-с-обменом (compare-and-swap). Однако и у тех и у других есть свои слабые места. О них мы и поговорим.
Из доклада вы узнаете, чем блокирующие алгоритмы отличаются от неблокирующих, и какими достоинствами и недостатками обладает каждый из этих классов. Кроме того, будут показаны различные подводные камни тех и других решений: Deadlock, Livelock, Starvation, Mutable vs Immutable hype.
Слайды доклада на конференции C++ Corehard Winter 2017 (г.Минск).
Автор доклада давно и успешно использует Модель Акторов при разработке приложений на C++. В основном это был положительный опыт. Но есть некоторые неочевидные моменты, про которые было бы хорошо узнать заранее. О том, где использование Модели Акторов уместно, а где нет, на какие грабли довелось наступить, какие шишки были набиты, как можно упростить себе жизнь и пойдет речь в докладе.
Доклад на конференциях JPoint 2016, JBreak 2016
Abstract: В Java SE 8 были добавлены лямбда-выражения, дефолтные методы, типовые аннотации, компактные профили и т.п., что привело к изменениям в спецификации Java SE платформы.
В этом докладе мы рассмотрим, как новые возможности, добавленные в Java 8, были реализованы в Excelsior JET JVM, полностью написанной с нуля, совершенно непохожей на Oracle HotSpot, но при этом совместимой со спецификацией Java SE.
В итоге, слушатель освежит в памяти, что появилось в Java 8, как это повлияло на спецификацию JVM, во что превращаются лямбда-выражения в Java байт-коде, как их можно статически оптимизировать, а также получит некоторое представление о внутреннем устройстве еще одной JVM.
Очередной скучный доклад про логгированиеPython Meetup
Стас Рудаков, компания СООО "Гейм Стрим"/Wargaming.net
Значение логов очень часто недооценивается, а зря. Доклад с оживленным диспутом со всеми участниками митапа, чтобы разобраться: как, куда и зачем писать логи. Помимо этого затронут вопрос, как из логов выжать больше информации.
Поговорим о рефлексии в C++, о том, что это такое, для чего нужно и почему это вообще важно. На практическом примере с котами рассмотрим эволюцию подходов к рефлексии в рамках разных версий языка: C++03, C++11/14, C++17. Посмотрим на то, что для нас готовят разработчики нового стандарта, узнаем где и как можно "пощупать" эти новые возможности. Поделимся полезными утилитами и подходами, которые облегчат жизнь пока эти новые возможности не придут к вам на проект.
Why do we need ORM? The difference between ActiveRecord and DataMapper patterns. The practical appliance of Iterative deepening depth-first search algo for topological sort of ORM relations.
Review of Cycle ORM and it features.
PG Day'14 Russia, PostgreSQL: архитектура, настройка и оптимизация, Илья Косм...pgdayrussia
Доклад был представлен на официальной российской конференции PG Day'14 Russia, посвященной вопросам разработки и эксплуатации PostgreSQL.
Основные принципы устройства PostgreSQL, ключевые принципы правильного конфигурирования и подходы к оптимизации под высокие нагрузки — обо всем этом Илья поведает на специальном мастер-классе, посвященном "внутренностям" СУБД. Курс предназначен как для опытных профессионалов, так и для "молодых бойцов". Полученные в ходе прослушивания семинара знания пригодятся не только на практике. Они также призваны увеличить эффективность восприятия слушателями и, как следствие, полезность докладов, запланированных на второй день конференции.
Как база работает с памятью и файловой системой? Для чего предназначено версионирование? Что такое транзакции, как они устроены и почему полезны? Как строятся индексы и что происходит с запросом во время его выполнения? Что такое репликация и почему ее нельзя применять для backup/recovery? На все эти вопросы, и не только, ответит Илья.
Разобравшись с основами и "матчастью", мы перейдем к самому интересному: "тюнингу" базы в нагруженных системах, начиная с классического "Почему у меня тормозит запрос?" и заканчивая кручением "гаек" системных процессов "посгреса" под объемы данных и транзакционные нагрузки, соизмеримые с "big data".
Консервативный Backend на Node.js / Дмитрий Ляпин (Recrumatic)Ontico
РИТ++ 2017, Backend Conf
Зал Кейптаун, 5 июня, 14:00
Тезисы:
http://backendconf.ru/2017/abstracts/2510.html
Я расскажу об опыте разработки REST API сервиса одной рекрутинговой платформы. Стремясь найти простое и масштабируемое решение, мы выбираем PostgreSQL и Node.js, а вместо сессий используем JWT-токены. Избегая ORM, мы пишем большие и сложные, но эффективные SQL-запросы. На помощь приходят SQL-представления, триггеры и небольшая собственная JS-библиотека.
...
Ангелы и демоны многопоточного программирования / Алексей Федоров (Одноклассн...Ontico
Современные процессоры имеют на борту по нескольку вычислительных ядер, позволяющих запускать задачи на них параллельно. И, казалось бы, вот оно — счастье: бей большие задачи на куски, запускай эти куски параллельно на разных ядрах и радуйся.
Но не все так просто. Для того чтобы одновременный доступ к общим данным выполнялся корректно, современные системы используют разные примитивы синхронизации. В основе одних лежат блокировки (locks), в основе других — операции типа сравнение-с-обменом (compare-and-swap). Однако и у тех и у других есть свои слабые места. О них мы и поговорим.
Из доклада вы узнаете, чем блокирующие алгоритмы отличаются от неблокирующих, и какими достоинствами и недостатками обладает каждый из этих классов. Кроме того, будут показаны различные подводные камни тех и других решений: Deadlock, Livelock, Starvation, Mutable vs Immutable hype.
Слайды доклада на конференции C++ Corehard Winter 2017 (г.Минск).
Автор доклада давно и успешно использует Модель Акторов при разработке приложений на C++. В основном это был положительный опыт. Но есть некоторые неочевидные моменты, про которые было бы хорошо узнать заранее. О том, где использование Модели Акторов уместно, а где нет, на какие грабли довелось наступить, какие шишки были набиты, как можно упростить себе жизнь и пойдет речь в докладе.
Доклад на конференциях JPoint 2016, JBreak 2016
Abstract: В Java SE 8 были добавлены лямбда-выражения, дефолтные методы, типовые аннотации, компактные профили и т.п., что привело к изменениям в спецификации Java SE платформы.
В этом докладе мы рассмотрим, как новые возможности, добавленные в Java 8, были реализованы в Excelsior JET JVM, полностью написанной с нуля, совершенно непохожей на Oracle HotSpot, но при этом совместимой со спецификацией Java SE.
В итоге, слушатель освежит в памяти, что появилось в Java 8, как это повлияло на спецификацию JVM, во что превращаются лямбда-выражения в Java байт-коде, как их можно статически оптимизировать, а также получит некоторое представление о внутреннем устройстве еще одной JVM.
Очередной скучный доклад про логгированиеPython Meetup
Стас Рудаков, компания СООО "Гейм Стрим"/Wargaming.net
Значение логов очень часто недооценивается, а зря. Доклад с оживленным диспутом со всеми участниками митапа, чтобы разобраться: как, куда и зачем писать логи. Помимо этого затронут вопрос, как из логов выжать больше информации.
Поговорим о рефлексии в C++, о том, что это такое, для чего нужно и почему это вообще важно. На практическом примере с котами рассмотрим эволюцию подходов к рефлексии в рамках разных версий языка: C++03, C++11/14, C++17. Посмотрим на то, что для нас готовят разработчики нового стандарта, узнаем где и как можно "пощупать" эти новые возможности. Поделимся полезными утилитами и подходами, которые облегчат жизнь пока эти новые возможности не придут к вам на проект.
Why do we need ORM? The difference between ActiveRecord and DataMapper patterns. The practical appliance of Iterative deepening depth-first search algo for topological sort of ORM relations.
Review of Cycle ORM and it features.
Как мы разрабатываем новый фронтенд / Филипп Нехаев (Tinkoff.ru)Ontico
Недавно запустили новый сайт Тинькофф.
У нас есть желание поделиться с аудиторией подходом и опытом разработки большого изоморфного приложения на React.js и Flux. Меньше чем за год мы разработали новый сайт и интернет-банк, заложив платформу на ближайшие несколько лет для быстрой разработки фронтенда новых продуктов.
Сейчас tinkoff.ru насчитывает более 3000 компонентов и сотни страниц.
Промышленный подход к тюнингу PostgreSQL: эксперименты над базами данныхNikolay Samokhvalov
Shared_buffers = 25% – это много или мало? Или в самый раз? Как понять, подходит ли эта – довольно устаревшая – рекомендация в вашем конкретном случае?
Пришло время подойти к вопросу подбора параметров postgresql.conf "по-взрослому". Не с помощью слепых "автотюнеров" или устаревших советов из статей и блогов, а на основе:
строго выверенных экспериментов на БД, производимых автоматизированно, в больших количествах и в условиях, максимально приближенных к "боевым",
глубокого понимания особенностей работы СУБД и ОС.
Используя Nancy CLI (https://gitlab.com/postgres.ai/nancy), мы рассмотрим конкретный пример – пресловутые shared_buffers – в разных ситуациях, в разных проектах и попробуем разобраться, как же подобрать оптимальную настройку для нашей инфраструктуры, БД и нагрузки.
https://pgconf.ru/2019/242809
Когда проект делает один разработчик — все просто. Когда над ним работает небольшая команда, можно синхронизироваться и договориться. А вот когда проектов (сайтов и приложений) становится много, и над ними трудится множество команд с перекрестной функциональностью и смежными зонами ответственности, все становится сложным и запутанным.
Я расскажу о своем виденье архитектуры фронтенда, какой она должна быть, чтобы обеспечить её масштабируемость. На основе своего опыта и проблем, с которыми сталкиваются большие проекты.
Видео: https://www.youtube.com/watch?list=PLknJ4Vr6efQFtZmsXmGG64Rz_PHrcXCBL&v=z9y6PNC2FL0
мониторинг производительности Web приложений на pythonSlach
как понять где тормозит твое приложение в реальном времени? как не потеряться в океане метрик и собрать на дашборде только нужные? видео https://youtu.be/JgezdgtoNG8
Andrey Borodin "Architecture of online backup for various DBMS"Fwdays
We are developing WAL-G, a cloud backup tool. We used to have only copies of PostgreSQL, but now we support MongoDB, MySQL, FoundationDB and others.
In this talk, I will talk about the features and differences of these databases in terms of backup in the Cloud.
Случалось ли, что вы видели (чужой) код и хотели все переписать? Бывало такое, что вы не могли понять, почему кем-то было принято конкретное решение, не другое? Хотели ли вы воскликнуть:«А я бы сделал еще круче!»?
Если вы задумывались об этом, вам будет интересно послушать историю о том, как эти вопросы возникали у Александра и Кирилла и как они решались в условиях большой компании.
Разработчики расскажут, как в самом начале пути вытаскивали шашки и шли в атаку на проблемную архитектуру. Но все оказалось не так просто, и по мере погружения в проект парни стали понимать, что архитектура большой системы — компромисс между различными подходами и решениями, инновациями и легаси (наследованным кодом), централизацией и децентрализацией компонентов. Докладчики наработали очень много опыта в решении архитектурных задач и поделятся опытом и выработанными принципами, которых придерживаются в настоящее время.
Во время доклада будут обсуждаться непростые вопросы, возникающие при принятии решений о том, как будет жить и эволюционировать система.
Вместе со слушателями Александр и Кирилл проделают упражнение по созданию «таблицы технологий» и её эволюции. Также они покажут, насколько важно инженерное решение на любой из стадий развития системы.
23. Предыстория 23
Условия
● Middle занимается сбором данных из различных источников
● Время ответа различных источников может сильно
различаться и нам неподконтрольно
24. Предыстория 24
Желания
● Хотим удобную, параллельную загрузку данных с
возможностью обработки по мере их готовности
● Хотим сами отдавать данные по мере их готовности
25. Предыстория 25
Желания
● Хотим удобную, параллельную загрузку данных с
возможностью обработки по мере их готовности
● Хотим сами отдавать данные по мере их готовности
28. Ищем варианты 28
Pull-based стратегия
● Подходит для случаев, когда данные готовы, например,
параллельные вычисления
29. Ищем варианты 29
Pull-based стратегия
● Подходит для случаев, когда данные готовы, например,
параллельные вычисления
● На ней основаны j.u.Stream и Fork/Join-фреймворки
30. Ищем варианты 30
Pull-based стратегия
● Подходит для случаев, когда данные готовы, например,
параллельные вычисления
● На ней основаны j.u.Stream и Fork/Join-фреймворки
● Плохо подходит для случаев с внешними блокирующими
вызовами
35. Ищем варианты 35
Push-based стратегия
● Подходит для случаев с блокирующими вызовами
● Сложнее модель исполнения в многопоточности
● Сложнее контролировать ресурсы для исполнения
36. Ищем варианты 36
Push-based стратегия
● Подходит для случаев с блокирующими вызовами
● Сложнее модель исполнения в многопоточности
● Сложнее контролировать ресурсы для исполнения
● На ней основан CompletableFuture
37. Ищем варианты 37
Push-based. Посмотреть
CompletableFuture in Java 8, asynchronous processing done right
(Tomasz Nurkiewicz)
38. Ищем варианты 38
А можно и то и другое?
The masochist-only CountedCompleter class requires manual
continuation passing transforms of fork/join style processing that can
co-exist with reactive processing.
Doug Lea
39. Ищем варианты 39
А если очень хочется?
And there exists a hybrid solution that we use in "Reactive Streams",
which at runtime dynamically switches between push and pull
depending on if the consumer can't keep up or the producer can't keep
up, without having to block or do any load-shedding.
Viktor Klang
40. Ищем варианты 40
Reactive Streams
Инициатива в попытке создать стандарт для асинхронной
обработки данных с возможностью неблокирующего контроля над
нагрузкой (backpressure).
41. Ищем варианты 41
Reactive Streams. Реализации
● Akka streams
● Project reactor
● ReactiveX (RxJava, RxScala, RxJs, etc.)
43. Ищем варианты 43
А если честно...
● Модель RxJava выглядит проще и привычнее акторов
44. Ищем варианты 44
А если честно...
● Модель RxJava выглядит проще и привычнее акторов
● Reactor выглядит скорее как основа для фреймворков
45. Ищем варианты 45
А если честно...
● Модель RxJava выглядит проще и привычнее акторов
● Reactor выглядит скорее как основа для фреймворков
● RxJava - одна библиотека весом в 1Mb без доп. зависимостей
46. Ищем варианты 46
А если честно...
● Модель RxJava выглядит проще и привычнее акторов
● Reactor выглядит скорее как основа для фреймворков
● RxJava - одна библиотека весом в 1Mb без доп. зависимостей
● Документация по ReactiveX
79. Обзор RxJava 79
SubscribeOn. Дважды
Observable.range(1,1000)
.subscribeOn(Schedulers.io())
.map(res -> res + 1)
.flatMap(res -> Observable.just(res))
.subscribeOn(Schedulers.computation())
.subscribe(result -> System.out.println(result))
80. Обзор RxJava 80
SubscribeOn. Рекомендации
Не стоит добавлять subscribeOn внутри своих библиотек, так как
пользователи не смогут переопределить заданное поведение.
87. Обзор RxJava 87
ObserveOn. Разбиваем дальше
observeOn
range Subscribermap flatMap
Threads from Scheduler by subscribeOn
observeOn
88. Обзор RxJava 88
Роль методов
● subscribeOn - отвечает за pool, на котором исполняется
Producer
89. Обзор RxJava 89
Роль методов
● subscribeOn - отвечает за pool, на котором исполняется
Producer
● observeOn - отвечает за pool, на котором исполняются
операторы и подписчик
107. Что там под капотом 107
Основы изучены
● Написание простейших цепочек
● Распределение работы по потокам
● Балансировка нагрузки через backpressure
108. Что там под капотом 108
Немного углубимся
В большинстве случаев вам хватит стандартного набора
операторов, но рано или поздно захочется расширить
функциональность.
109. Что там под капотом 109
Observable.Operator
Observable.Operator<Integer, Integer> operator = subscriber -> {
new Subscriber<Integer>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(Integer integer) {
//do some work
}
};
110. Что там под капотом 110
Пишем свой оператор
Observable.Operator<Integer, Integer> filter100 = subscriber -> {
return new Subscriber<Integer>() {
public void onNext(Integer el) {
if(el < 100)
subscriber.onNext(el);
else
onCompleted();
}
…
};
111. Что там под капотом 111
Встраиваем оператор
Observable.range(1,1000)
.lift(filter100)
.observeOn(Schedulers.newThread())
.flatMap(res -> someBlockingCall())
.subscribe(result -> System.out.println(result));
112. Что там под капотом 112
Работает!
Еще и многопоточно!
113. Что там под капотом 113
Немного подправим оператор
Observable.range(1,1000)
.lift(filter200)
.observeOn(Schedulers.newThread())
.flatMap(res -> someBlockingCall(res))
.subscribe(res -> System.out.println(res));
114. Что там под капотом 114
Упс!
rx.exceptions.MissingBackpressureException
116. Что там под капотом 116
Разрыв обратной связи
range flatMap
onXXX
filter200
onXXX
117. Что там под капотом 117
Исправляем оператор
Observable.Operator<Integer, Integer> filter100 = subscriber -> {
return new Subscriber<Integer>(subscriber) {
public void onNext(Integer el) {
if(el < 200)
subscriber.onNext(el);
else
onCompleted();
}
…
};
118. Что там под капотом 118
А почему работало?
Внутри обертки OperatorObserveOn есть Queue размером в 128
элементов, потому что backpressure был не всегда.
119. Что там под капотом 119
А почему 128?
Читайте benchmark в комментариях к очереди в observeOn :)
120. Что там под капотом 120
Оператор пропуска нечетных
Observable.Operator<Integer, Integer> skipOdd = subs -> {
return new Subscriber<Integer>(subs) {
public void onNext(Integer i) {
if (i % 2 == 0)
subs.onNext(i);
}
...
};
121. Что там под капотом 121
Подключаем оператор
Observable.Operator<Integer, Integer> skipOdd = subs -> {
return new Subscriber<Integer>(subs) {
public void onNext(Integer i) {
if (i % 2 == 0)
subs.onNext(i);
}
...
};
Observable.range(1, 100)
.lift(skipOdd)
.take(10)
.subscribe(res -> System.out.println(res));
122. Что там под капотом 122
Вывод. Чего-то не хватает
2
4
6
8
10
123. Что там под капотом 123
Вспоминаем про backpressure
Observable.Operator<Integer, Integer> skipOdd = subs -> {
return new Subscriber<Integer>(subs) {
public void onNext(Integer i) {
if (i % 2 == 0)
subs.onNext(i);
else
request(1);
}
...
};
124. Что там под капотом 124
Продолжаем писать оператор
Operator<Integer, Integer> filter200 = subscriber -> {
return new Subscriber<Integer>() {
public void onNext(Integer el) {
if(el < 200)
subscriber.onNext(el);
else
onCompleted();
}
public void onCompleted() {
subscriber.onCompleted();
unsubscribe();
}
…
};
125. Что там под капотом 125
Есть потоки, есть проблемы
Operator<Integer, Integer> filter200 = subscriber -> {
return new Subscriber<Integer>() {
public void onNext(Integer el) {
if(el < 200)
subscriber.onNext(el);
else
onCompleted();
}
public void onCompleted() {
subscriber.onCompleted();
unsubscribe();
}
…
};
Thread 1
126. Что там под капотом 126
Есть потоки, есть проблемы
Operator<Integer, Integer> filter200 = subscriber -> {
return new Subscriber<Integer>() {
public void onNext(Integer el) {
if(el < 200)
subscriber.onNext(el);
else
onCompleted();
}
public void onCompleted() {
subscriber.onCompleted();
unsubscribe();
}
…
};
Thread 1
Thread 2
127. Что там под капотом 127
Гарантии #1-2
● События onNext, onError и onComplete должны быть доставлены в
Subscriber последовательно
128. Что там под капотом 128
Гарантии #1-2
● События onNext, onError и onComplete должны быть доставлены в
Subscriber последовательно
● События onError и onCompleted терминальны
129. Что там под капотом 129
Добавляем сериализацию
Operator<Integer, Integer> filter200 = c -> {
Subscriber<Integer> subscriber = new SerializedSubscriber<>(c);
return new Subscriber<Integer>() {
public void onNext(Integer el) {
if(el < 100)
subscriber.onNext(el);
else
onCompleted();
}
public void onCompleted() {
subscriber.onCompleted();
unsubscribe();
}
…
};
130. Что там под капотом 130
Есть потоки, нет проблем
Observable.range(1,1000)
.lift(filter200)
.flatMap(sources -> loadPreferences(sources))
.observeOn(Schedulers.io())
.subscribe(res -> System.out.println(res))
131. Что там под капотом 131
Serialization
if (emitting) {
global = value;
return;
}
emitting = true;
synchronized(this)
Value
132. Что там под капотом 132
Serialization
if (emitting) {
global = value;
return;
}
emitting = true;
if (global == null) {
emitting = false;
return;
}
result = global;
global = null;
synchronized(this) synchronized(this)
Value
133. Что там под капотом 133
Serialization
if (emitting) {
global = value;
return;
}
emitting = true;
T result;
consumer.accept(result)
if (global == null) {
emitting = false;
return;
}
result = global;
global = null;
synchronized(this) synchronized(this)
Value
for (;;)
Value
134. Что там под капотом 134
Serialization
if (emitting) {
??? q = queue;
if (q == null) {
q = new ???();
queue = q;
}
q.add(event);
return;
}
emitting = true;
synchronized(this)
135. Что там под капотом 135
Serialization
q = queue;
if (q == null) {
emitting = false;
return;
}
queue = null;
synchronized(this)if (emitting) {
??? q = queue;
if (q == null) {
q = new ???();
queue = q;
}
q.add(event);
return;
}
emitting = true;
synchronized(this)
136. Что там под капотом 136
Serialization
??? q;
q.forEach(consumer);
q = queue;
if (q == null) {
emitting = false;
return;
}
queue = null;
synchronized(this)if (emitting) {
??? q = queue;
if (q == null) {
q = new ???();
queue = q;
}
q.add(event);
return;
}
emitting = true;
synchronized(this)
for (;;)
137. Что там под капотом 137
Serialization
List q;
q.forEach(consumer);
q = queue;
if (q == null) {
emitting = false;
return;
}
queue = null;
synchronized(this)if (emitting) {
List q = queue;
if (q == null) {
q = new ArrayList();
queue = q;
}
q.add(event);
return;
}
emitting = true;
synchronized(this)
for (;;)
138. Что там под капотом 138
Serialization. Emitter-loop
139. Что там под капотом 139
Serialization. Emitter-loop
− Блокирующий
140. Что там под капотом 140
Serialization. Emitter-loop
− Блокирующий
+ Могут происходить оптимизации Biased locking и Lock elision
141. Что там под капотом 141
Serialization. Emitter-loop
− Блокирующий
+ Могут происходить оптимизации Biased locking и Lock elision
● Работает внутри RxJava version 1.X
142. Что там под капотом 142
Serialization. Queue-drain
final Queue<T> queue = new ????Queue<>();
final AtomicInteger wip = new AtomicInteger();
public void drain(T value) {
queue.offer(Objects.requireNonNull(value)); // (1)
if (wip.getAndIncrement() == 0) {
do {
wip.set(1);
T v;
while ((v = queue.poll()) != null) {
consumer.accept(v);
}
} while (wip.decrementAndGet() != 0);
}
}
143. Что там под капотом 143
Serialization. Queue-drain
final Queue<T> queue = new ????Queue<>();
final AtomicInteger wip = new AtomicInteger();
public void drain(T value) {
queue.offer(Objects.requireNonNull(value));
if (wip.getAndIncrement() == 0) {
do {
wip.set(1);
T v;
while ((v = queue.poll()) != null) {
consumer.accept(v);
}
} while (wip.decrementAndGet() != 0);
}
}
144. Что там под капотом 144
Serialization. Queue-drain
final Queue<T> queue = new ????Queue<>();
final AtomicInteger wip = new AtomicInteger();
public void drain(T value) {
queue.offer(Objects.requireNonNull(value));
if (wip.getAndIncrement() == 0) {
do {
wip.set(1);
T v;
while ((v = queue.poll()) != null) {
consumer.accept(v);
}
} while (wip.decrementAndGet() != 0);
}
}
145. Что там под капотом 145
Serialization. Queue-drain
final Queue<T> queue = new ????Queue<>();
final AtomicInteger wip = new AtomicInteger();
public void drain(T value) {
queue.offer(Objects.requireNonNull(value));
if (wip.getAndIncrement() == 0) {
do {
wip.set(1);
T v;
while ((v = queue.poll()) != null) {
consumer.accept(v);
}
} while (wip.decrementAndGet() != 0);
}
}
146. Что там под капотом 146
Serialization. Queue-drain
final Queue<T> queue = new ????Queue<>();
final AtomicInteger wip = new AtomicInteger();
public void drain(T value) {
queue.offer(Objects.requireNonNull(value));
if (wip.getAndIncrement() == 0) {
do {
wip.set(1);
T v;
while ((v = queue.poll()) != null) {
consumer.accept(v);
}
} while (wip.decrementAndGet() != 0);
}
}
147. Что там под капотом 147
Serialization. Queue-drain
final Queue<T> queue = new ????Queue<>();
final AtomicInteger wip = new AtomicInteger();
public void drain(T value) {
queue.offer(Objects.requireNonNull(value));
if (wip.getAndIncrement() == 0) {
do {
wip.set(1);
T v;
while ((v = queue.poll()) != null) {
consumer.accept(v);
}
} while (wip.decrementAndGet() != 0);
}
}
148. Что там под капотом 148
Serialization. Queue-drain
final Queue<T> queue = new MpscLinkedQueue<>();
final AtomicInteger wip = new AtomicInteger();
public void drain(T value) {
queue.offer(Objects.requireNonNull(value));
if (wip.getAndIncrement() == 0) {
do {
wip.set(1);
T v;
while ((v = queue.poll()) != null) {
consumer.accept(v);
}
} while (wip.decrementAndGet() != 0);
}
}
149. Что там под капотом 149
MpscLinkedQueue
● Multiple producer Single consumer очередь из пакета JCTools
150. Что там под капотом 150
MpscLinkedQueue
● Multiple producer Single consumer очередь из пакета JCTools
● Wait-free offer и Lock-free poll
151. Что там под капотом 151
MpscLinkedQueue. Почитать
Porting Pitfalls:
Turning D.Vyukov MPSC Wait-free queue into a j.u.Queue
152. Что там под капотом 152
Serialization. Queue-drain
+ Почти неблокирующий
153. Что там под капотом 153
Serialization. Queue-drain
+ Почти неблокирующий
● Работает внутри RxJava version 2.X
161. А дальше? 161
Дальнейшие шаги
● Chunked Transfer Encoding для передачи данных по частям
● Non-blocking NIO и Async Servlet
162. Выводы 162
Выводы
● Базовый набор операторов RxJava прост и удобен для
построения цепочек сбора и обработки данных
163. Выводы 163
Выводы
● Базовый набор операторов RxJava прост и удобен для
построения цепочек сбора и обработки данных
● Писать свои операторы просто, но надо понимать механику,
ошибки могут запомниться вам надолго
164. Выводы 164
Выводы
● Базовый набор операторов RxJava прост и удобен для
построения цепочек сбора и обработки данных
● Писать свои операторы просто, но надо понимать механику,
ошибки могут запомниться вам надолго
● Rx-цепочки внутри синхронного приложения не являются
полноценным решением
165. Почитать / Посмотреть 165
Почитать / Посмотреть
● http://www.reactivemanifesto.org/ - прочитать и подписать
● https://github.com/reactive-streams/reactive-streams-jvm/
● http://reactivex.io/ - документация ReactiveX
● https://github.com/ReactiveX/RxJava/wiki - wiki проекта
● http://akarnokd.blogspot.ru/ - блог о внутренностях RxJava
● http://tomstechnicalblog.blogspot.ru/ - понятные объяснения