Реактивно програмиране на java. Реактивно програмиране в Objective-C

Искам да ви разкажа за една съвременна програмна дисциплина, която отговаря на нарастващите изисквания за мащабируемост, устойчивост на грешки и бърза реакция и е незаменима както в многоядрени среди, така и в облачни изчисления, както и да представи отворен онлайн курс по него, който ще започне само след няколко дни.

Ако не сте чували за реактивно програмиране, Всичко е наред. Това е бързо развиваща се дисциплина, която съчетава едновременност с управлявано от събития и асинхронно. Реактивността е присъща на всяка уеб услуга и разпределена система и е ядрото на много високопроизводителни системи с висока степен на паралелност. Накратко, авторите на курса предлагат да се разглежда реактивното програмиране като естествено разширение на функционалното програмиране (с функции от по-висок ред) към паралелни системи с разпределено състояние, координирани и оркестрирани от асинхронни потоци от данни, обменяни от активни субекти, или актьори.

С по-разбираеми думи това е описано в Реактивния манифест, по-долу ще преразкажа основните положения от него, а пълният превод е публикуван на Хабре. Както се казва в Уикипедия, терминът реактивно програмиранесъществува от дълго време и практически приложенияразлична степен на екзотичност, но съвсем наскоро получи нов тласък за развитие и разпространение, благодарение на усилията на авторите на Reactive Manifesto, инициативна група от Typesafe Inc. Typesafe е известна в общността на функционалното програмиране като компанията, основана от авторите на отличния език Scala и революционната паралелна платформа Akka. Сега те позиционират своята компания като създател на първата в света реактивна платформа, предназначена да разработи ново поколение. Тяхната платформа ви позволява бързо да разработите комплекс потребителски интерфейсии осигурява ново ниво на абстракция спрямо паралелните изчисления и многонишковостта, като намалява присъщите им рискове чрез гарантирано предвидимо мащабиране. Той прилага на практика идеите на Reactive Manifesto и позволява на разработчика да разбере и създаде приложения, които отговарят на днешните нужди.

Можете да се запознаете с тази платформа и реактивното програмиране, като вземете участие в масовия отворен онлайн курс на Reactive Principles. Този курс е продължение на курса на Мартин Одерски „Принципи на функционалното програмиране в Scala“, който има над 100 000 участници и демонстрира един от най-високите проценти на успеваемост за масов отворен онлайн курс от неговите участници в света. Заедно със създателя на езика Scala, новият курс се преподава от Ерик Майер, който разработи Rx framework за реактивно програмиране под .NET, и Роланд Кун, който в момента ръководи екипа за разработка на Akka в Typesafe. Курсът обхваща ключовите елементи на реактивното програмиране и показва как те се прилагат за проектиране на управлявани от събития системи, които са мащабируеми и устойчиви на грешки. Учебният материал е илюстриран кратки програмии се придружава от набор от задачи, всяка от които е софтуерен проект. При успешно изпълнение на всички задачи участниците получават сертификати (разбира се, участието и сертификатите са безплатни). Курсът продължава 7 седмици и започва този понеделник, 4 ноември. Подробно описание, както и уводно видео са достъпни на страницата на курса: https://www.coursera.org/course/reactive.

За тези, които се интересуват или се съмняват, предлагам кратко резюме на основните концепции на Reactive Manifesto. Неговите автори отбелязват значителни промени в изискванията за заявленията за последните години. Днес приложенията се внедряват във всяка среда от мобилни устройствакъм облачни клъстери с хиляди многоядрени процесори. Тези среди поставят нови изисквания софтуери технологии. Архитектурите от предишно поколение се фокусираха върху управлявани сървъри и контейнери, мащабиране чрез допълнителен скъп хардуер, патентовани решения и паралелно изчислениечрез многопоточност. В момента се разработва нова архитектура, която има четири ключови характеристики, които са все по-разпространени както в потребителската, така и в корпоративната индустриална среда. Системите с тази архитектура са: управлявани от събития, мащабируеми, устойчиви на грешки (Resilient) и имат бърза реакция, т.е. отзивчив (Отзивчив). Това осигурява безпроблемно потребителско изживяване в реално време, поддържано от самовъзстановяващ се, мащабируем стек от приложения, който е готов за внедряване в многоядрени и облачни среди. Всяка от четирите характеристики на реактивната архитектура се прилага към целия технологичен стек, което ги отличава от връзките в многослойните архитектури. Нека ги разгледаме малко по-подробно.


Водени от събитияприложенията приемат комуникации с асинхронни компоненти и прилагат техния слабо свързан дизайн: изпращачът и получателят на съобщението не трябва да знаят нито един за друг, нито за метода на предаване на съобщението, което им позволява да се концентрират върху съдържанието на комуникациите. В допълнение към факта, че слабо свързаните компоненти значително подобряват поддържаемостта, разширяемостта и еволюцията на системата, асинхронният и неблокиращ характер на тяхното взаимодействие може също да освободи значителна част от ресурсите, да намали времето за реакция и да осигури ОПовече ▼ пропускателна способноств сравнение с традиционните приложения. Благодарение на природата, управлявана от събития, са възможни останалите характеристики на реактивната архитектура.

Мащабируемоств контекста на реактивното програмиране, това е реакцията на системата към промяна в натоварването, т.е. еластичност, постигната чрез възможността за добавяне или освобождаване на изчислителни възли според нуждите. С ниско свързване, асинхронно изпращане на съобщения и прозрачност на местоположението, методът на внедряване и топологията на приложението се превръщат във времево решение за внедряване и подлежат на реагираща на натоварване конфигурация и адаптивни алгоритми. По този начин, компютърна мрежастава част от приложението, като първоначално има явно разпределен характер.

отказоустойчивостреактивната архитектура също става част от дизайна и това я прави значително по-различна от традиционните подходи за осигуряване на непрекъсната наличност на системата чрез резервиране на сървъра и отказ. Устойчивостта на такава система се постига чрез способността й да реагира правилно на повреди на отделни компоненти, да изолира тези повреди, като съхранява техния контекст под формата на съобщения, които са ги причинили, и предава тези съобщения на друг компонент, който може да взема решения за това как да обработете грешката. Този подход ви позволява да поддържате бизнес логиката на приложението чиста, отделяйки от нея логиката на обработка на откази, която е формулирана в изрична декларативна форма за регистриране, изолиране и обработка на откази от средствата на самата система. За да се изградят такива системи за самовъзстановяване, компонентите се подреждат йерархично и проблемът се ескалира до нивото, което може да го разреши.

И накрая отзивчивост- това е способността на системата да реагира на въвеждане на потребителя, независимо от натоварването и повреди, такива приложения включват потребителя във взаимодействие, създават усещане тясна връзкасъс система и достатъчно оборудване за изпълнение на текущи задачи. Отзивчивостта е уместна не само в системите в реално време, но е необходима и за широк спектър от приложения. Освен това система, която не е в състояние да реагира бързо дори в момента на повреда, не може да се счита за устойчива на грешки. Отзивчивостта се постига чрез използване на наблюдаеми модели, потоци от събития и клиенти със състояние. Наблюдаемите модели излъчват събития, когато тяхното състояние се промени и осигуряват взаимодействие в реално време между потребители и системи, докато потоците от събития осигуряват абстракцията, върху която това взаимодействие е изградено чрез неблокиращи асинхронни трансформации и комуникации.

По този начин реактивните приложения представляват балансиран подход към решаването на широк спектър от проблеми на съвременното разработване на софтуер. Изградени върху основа, управлявана от събития, те предоставят инструментите, необходими за гарантиране на мащабируемост и устойчивост на грешки и поддържат пълнофункционално отзивчиво потребителско изживяване. Авторите очакват всичко това Повече ▼системите ще се придържат към принципите на реактивния манифест.

Освен това давам плана на курса без превод. Само в случай, че сте прочели до тук и все още сте любопитни.

Седмица 1: Преглед на принципите на функционалното програмиране: модел на заместване, for-изрази и как те се отнасят към монадите. Въвежда нова реализация на for-изрази: генератори на произволни стойности. Показва как това може да се използва при рандомизирано тестване и дава общ преглед на ScalaCheck, инструмент, който прилага тази идея.

Седмица 2: Функционално програмиране и променливо състояние. Какво прави един обект променлив? Как това се отразява на модела на заместване. Разширен пример: Симулация на цифрова верига

Седмица 3: фючърси. Въвежда фючърси като друга монада, с for-изрази като конкретен синтаксис. Показва как могат да бъдат съставени фючърси, за да се избегне блокиране на нишки. Обсъжда обработката на грешки при кръстосани нишки.

Седмица 4: Реактивна обработка на потока. Обобщаване на фючърси към реактивни изчисления върху потоци. оператори на потоци.

Седмица 5: Актьори. Представя модела на актьора, актьорите като капсулирани единици на последователност, асинхронно предаване на съобщения, обсъжда различни семантики на доставка на съобщения (най-много веднъж, поне веднъж, точно веднъж) и евентуална последователност.

Седмица 6: надзор. Въвежда конкретизация на повреда, йерархична обработка на повреда, модел на ядрото на грешката, мониторинг на жизнения цикъл, обсъжда преходно и постоянно състояние.

Седмица 7: Модели на разговор. Обсъжда управлението на състоянието на разговор между участниците и моделите за контрол на потока, маршрутизирането на съобщенията към групите участници за устойчивост или балансиране на натоварването, потвърждение за получаване за постигане на надеждна доставка.

Светът на ООП разработката като цяло и езикът Java в частност живеят много активен живот. Той има свои собствени модни тенденции и днес ще анализираме една от основните тенденции на сезона - рамката ReactiveX. Ако все още сте встрани от тази вълна - обещавам, че ще ви хареса! Определено е по-добре от дънки с висока талия :).

Реактивно програмиране

Веднага след като OOP езиците са узрели за масова употреба, разработчиците са осъзнали колко много понякога липсват възможностите на C-подобните езици. Тъй като писането на код в стила на функционалното програмиране сериозно разрушава качеството на ООП кода, а оттам и поддръжката на проекта, беше изобретен хибрид - реактивно програмиране.

Парадигмата за реактивно развитие се основава на идеята за постоянно проследяване на промените в състоянието на даден обект. Ако са настъпили такива промени, всички заинтересовани обекти трябва да получат вече актуализирани данни и да работят само с тях, забравяйки за старите.

Добър пример за идея за реактивно програмиране е електронна таблица в Excel. Ако свържете няколко клетки с една формула, резултатът от изчислението ще се променя всеки път, когато данните в тези клетки се променят. За счетоводството такава динамична промяна в данните е нещо обичайно, но за програмистите е по-скоро изключение.

А=3; b=4; c=a+b; F1(c); а=1; F2(c);

В този пример функциите F1 и F2 ще работят с различни стойности на променливата C. Често се изисква и двете функции да имат само най-актуалните данни - реактивното програмиране ще ви позволи незабавно да извикате F1 с нов параметри, без да се променя логиката на самите функции. Тази структура на кода дава възможност на приложението незабавно да реагира на всякакви промени, което ще го направи бързо, гъвкаво и отзивчиво.

ReactiveX

Внедряването на идеи за реактивно програмиране от нулата може да бъде доста обезпокоително - има клопки и ще отнеме доста време. Следователно за много разработчици тази парадигма остава само теоретичен материал до появата на ReactiveX.

Рамката ReactiveX е реактивен инструмент за програмиране, който работи с всички популярни ООП езици. Самите създатели го наричат ​​мултиплатформен API за асинхронна разработка, базиран на модела Observer.

Ако терминът "реактивно програмиране" е вид теоретичен модел, то моделът Observer е готов механизъм за проследяване на промените в програмата. И трябва да ги проследявате доста често: зареждане и актуализиране на данни, известия за събития и т.н.

Моделът Observer съществува приблизително толкова дълго, колкото и самият OOP. Обект, чието състояние може да се променя, се нарича издател (популярен превод на термина Observable). Всички други участници, които се интересуват от тези промени, са абонати (Наблюдател, Абонат). За да получават известия, абонатите се регистрират при издателя, като изрично посочват своя ID. Издателят от време на време генерира известия, които се изпращат от издателя до списъка с регистрирани абонати.

Всъщност създателите на ReactiveX не измислиха нищо революционно, те просто внедриха шаблона удобно. И въпреки че много ООП езици и в частност Java имат готови реализации на модела, тази рамка има допълнителна "настройка", която превръща "Наблюдателя" в много мощен инструмент.

RxAndroid

Портът на библиотеката ReactiveX за света на Android се нарича rxAndroid и е свързан, както винаги, чрез Gradle.

Компилирайте "io.reactivex:rxandroid:1.1.0"

Издателят, който генерира известия, се посочва тук с помощта на класа Observable. Един издател може да има няколко абонати; за да ги реализираме, ще използваме класа Subscriber. Поведението по подразбиране за Observable е да издаде едно или повече съобщения на абонатите и след това да излезе или да издаде съобщение за грешка. Съобщенията могат да бъдат както променливи, така и цели числа.

Rx.Observable myObserv = rx.Observable.create(нов rx.Observable.OnSubscribe () ( @Override публично невалидно повикване(Абонатабонат) ( абонат.onNext("Hello"); subscriber.onNext("свят"); subscriber.onCompleted(); ) ));

В този случай издателят myObserv първо ще изпрати низовете за приветствие и съобщение, а след това съобщение за успех. Издателят може да извика методите onNext(), onCompleted() и onEror(), така че абонатите трябва да ги дефинират.

Абонат mySub = нов абонат () (... @Override public void onNext(String value) (Log.e("got data", " " + value);) );

Всичко е готово за работа. Остава да свържете обектите един към друг - и "Hello, world!" в реактивното програмиране е готов!

MyObserv.subscribe(mySub);

Трябва да кажа, че това беше много прост пример. ReactiveX има много опции за поведението на всички участници в модела: филтриране, групиране, обработка на грешки. Ползите от реактивното програмиране могат да се усетят само като се изпробва в действие. Нека се заемем по-сериозно със задачата.

Продължава достъпно само за членове

Вариант 1. Присъединете се към общността на "сайт", за да прочетете всички материали на сайта

Членството в общността през посочения период ще ви даде достъп до ВСИЧКИ хакерски материали, ще увеличи личната ви кумулативна отстъпка и ще ви позволи да натрупате професионален рейтинг на Xakep Score!

Отивам.

Реактивното програмиране първоначално звучи като името на зараждаща се парадигма, но всъщност се отнася до метод на програмиране, който използва подход, управляван от събития, за работа с асинхронни потоци от данни. Въз основа на постоянно актуални данни, реактивните системи реагират на тях чрез изпълнение на поредица от събития.
Реактивното програмиране следва дизайнерския модел на наблюдателя, който може да се дефинира по следния начин: ако настъпи промяна на състоянието в един обект, всички останали обекти се уведомяват и съответно се актуализират. Така че вместо да проверяват събития за промени, събитията се изпращат асинхронно, така че наблюдателите да могат да ги обработват. В този пример наблюдателите са функции, които се изпълняват при изпращане на събитие. И споменатият поток от данни е действително наблюдаваният.

Почти всички езици и рамки използват този подход в своята екосистема и най-новите версии на Java не са изключение. В тази статия ще обясня как може да се приложи реактивно програмиране с помощта на най-новата версия на JAX-RS в Java EE 8 и функционалността на Java 8.

Реактивен манифест

Реактивният манифест изброява четири основни аспекта, от които едно приложение се нуждае, за да бъде по-гъвкаво, слабо свързано и лесно за мащабиране и следователно способно да бъде реактивно. Той казва, че приложението трябва да бъде отзивчиво, гъвкаво (и следователно мащабируемо), устойчиво и управлявано от съобщения.

Основната цел е наистина отзивчиво приложение. Да приемем, че имате приложение, което има една голяма нишка, обработваща потребителски заявки, и когато работата е свършена, тази нишка изпраща отговори обратно на първоначалните заявители. Когато дадено приложение получи повече заявки, отколкото може да обработи, този поток се превръща в пречка и приложението губи предишната си отзивчивост. За да остане отзивчиво, приложението трябва да бъде мащабируемо и устойчиво. Устойчиво приложение е това, което има функция за автоматично възстановяване. Според опита на повечето разработчици само управляваната от съобщения архитектура позволява на приложението да бъде мащабируемо, стабилно и отзивчиво.

Реактивното програмиране беше въведено в Java 8 и Java EE 8. Езикът Java въведе концепции като CompletionStage и неговата реализация CompletableFuture и Java започна да използва тези функции в спецификации като Reactive Client API в JAX-RS.

JAX-RS 2.1 API за реактивен клиент

Нека да разгледаме как реактивното програмиране може да се използва в приложенията на Java EE 8. За да разберете процеса, имате нужда от основни познания за Java EE API.

JAX-RS 2.1 въведе нов начин за създаване на реактивен REST клиент. Реализацията по подразбиране на invoker, предлагана от JAX-RS, е синхронна, което означава, че клиентът, който се създава, ще изпрати блокиращо повикване до крайната точка на сървъра. Примерна реализация е дадена в листинг 1.

Отговор на отговор = ClientBuilder.newClient() .target("http://localhost:8080/service-url") .request() .get();
Започвайки с версия 2.0, JAX-RS осигурява поддръжка за създаване на асинхронен инвокатор на клиентския API с просто извикване на метода async(), както е показано в списък 2.

Бъдеще отговор = ClientBuilder.newClient() .target("http://localhost:8080/service-url") .request() .async() .get();
Използването на асинхронен инвокатор на клиента връща Future екземпляр от тип javax.ws.rs.core.Response. Това може да доведе до запитване за отговор, извикване на future.get() или регистриране на обратно извикване, което ще бъде извикано, когато има наличен HTTP отговор. И двете реализации са подходящи за асинхронно програмиране, но нещата стават по-сложни, ако искате да групирате обратни извиквания или да добавите условни случаи към тези минимуми за асинхронно изпълнение.

JAX-RS 2.1 предоставя реактивен начин за преодоляване на тези проблеми с новия JAX-RS Reactive Client API за клиентско сглобяване. Това е толкова просто, колкото извикването на метода rx() по време на изграждането на клиента. В листинг 3 методът rx() връща реактивен инвокатор, който съществува по време на изпълнението на клиента, а клиентът връща отговор с тип CompletionStage.rx(), което позволява преход от синхронен инвокатор към асинхронен инвокатор с прост обадете се.

Етап на завършване отговор = ClientBuilder.newClient() .target("http://localhost:8080/service-url") .request() .rx() .get();
Етап на завършване<Т>е нов интерфейс, въведен в Java 8. Той представлява изчисление, което може да бъде стъпка в рамките на по-голямо изчисление, както подсказва името. Това е единствената реактивност на Java 8, която го направи в JAX-RS.
След като получа екземпляра на отговора, мога да извикам AcceptAsync(), където мога да осигуря част от кода, който ще бъде изпълнен асинхронно, когато отговорът стане достъпен, както е показано в листинг 4.

Response.thenAcceptAsync(res -> ( Temperature t = res.readEntity(Temperature.class); //правете неща с t ));
Добавяне на реактивност към REST крайна точка

Реактивният подход не е ограничен до страната на клиента в JAX-RS; може да се използва и от страната на сървъра. Като пример, първо ще създам прост скрипт, където мога да поискам списък с местоположения за една дестинация. За всяка позиция ще направя отделно обаждане с данните за местоположението до друга точка, за да получа температурните стойности. Взаимодействието на дестинациите ще бъде както е показано на фигура 1.

Фигура 1. Взаимодействие между дестинации

Първо просто дефинирам модела на домейна и след това услугите за всеки модел. Листинг 5 показва как е дефиниран класът Forecast, който обвива класовете Location и Temperature.

Публичен клас Температура (private Double temperature; private String scale; // getters & setters) public class Location ( String name; public Location() () public Location(String name) ( this.name = name; ) // getters & setters ) публичен клас Прогноза ( частно местоположение местоположение; частна температура на температурата; публична прогноза (местоположение на местоположение) ( this.location = местоположение; ) публична прогноза setTemperature (крайна температура на температурата) ( this.temperature = температура; върнете това; ) // получатели )
За да обвие списъка с прогнози, класът ServiceResponse е имплементиран в листинг 6.

Публичен клас ServiceResponse( частен дълго време за обработка; частен списък прогнози = нов ArrayList<>(); public void setProcessingTime(long processingTime) ( this.processingTime = processingTime; ) public ServiceResponse прогнози(Списък прогнози) ( this.forecasts = прогнози; върнете това; ) // получатели )
LocationResource, показан в листинг 7, дефинира три модела на местоположения, върнати с пътя /location.

@Path("/location") публичен клас LocationResource ( @GET @Produces(MediaType.APPLICATION_JSON) публичен отговор getLocations() ( Списък местоположения = нов ArrayList<>(); locations.add(ново местоположение("Лондон")); locations.add(ново местоположение("Истанбул")); locations.add(ново местоположение("Прага")); върне Response.ok(нов GenericEntity >(локации)()).build(); ) )
TemperatureResource, показан в листинг 8, връща произволно генерирана температурна стойност между 30 и 50 за даденото местоположение. Към изпълнението е добавено забавяне от 500 ms, за да се симулира отчитането на сензора.

@Path("/temperature") public class TemperatureResource ( @GET @Path("/(city)") @Produces(MediaType.APPLICATION_JSON) public Response getAverageTemperature(@PathParam("city") String cityName) ( Temperature temperature = new Temperature(); temperature.setTemperature((double) (new Random().nextInt(20) + 30)); temperature.setScale("Celsius"); try ( Thread.sleep(500); ) catch (InterruptedException игнорирано) (ignored.printStackTrace(); ) return Response.ok(temperature).build(); ) )
Първо, ще покажа имплементация на синхронен ForecastResource (вижте листинг 9), който връща всички местоположения. След това, за всяка позиция, той извиква температурната услуга, за да получи стойностите в градуси по Целзий.

@Path("/forecast") public class ForecastResource ( @Uri("location") private WebTarget locationTarget; @Uri("temperature/(city)") private WebTarget temperatureTarget; @GET @Produces(MediaType.APPLICATION_JSON) public Response getLocationsWithTemperature () ( long startTime = System.currentTimeMillis(); ServiceResponse response = new ServiceResponse(); List местоположения = locationTarget .request() .get(нов GenericType >()()); forEach(location -> ( Temperature temperature = temperatureTarget .resolveTemplate("city", location.getName()) .request() .get(Temperature.class); response.getForecasts().add(new Forecast(location) .setTemperature (температура)); )); дълго крайно време = System.currentTimeMillis(); response.setProcessingTime(endTime - startTime); връщане Response.ok(response).build(); ) )
Когато дестинацията на прогнозата е поискана като /forecast, ще получите изход, подобен на листинг 10. Обърнете внимание, че обработката на заявката отне 1,533 ms, което е логично, тъй като искането на температури от три различни местоположения синхронно добавя до 1,5 ms.

( "прогнози": [ ( "местоположение": ( "име": "Лондон" ), "температура": ( "скала": "Целзий", "температура": 33 ) ), ( "местоположение": ( "име ": "Истанбул"), "температура": ( "скала": "Целзий", "температура": 38)), ( "местоположение": ( "име": "Прага"), "температура": ( "скала ": "Целзий", "температура": 46 ) ) ], "Време за обработка": 1533 )
Засега всичко върви по план. Време е да се въведе реактивно програмиране от страната на сървъра, където повикванията към всяко местоположение могат да се правят паралелно, след като всички местоположения бъдат получени. Това може ясно да подобри синхронния поток, показан по-рано. Това се прави в листинг 11, който показва дефиницията на реактивна версия на прогнозната услуга.

@Path("/reactiveForecast") public class ForecastReactiveResource ( @Uri("location") private WebTarget locationTarget; @Uri("temperature/(city)") private WebTarget temperatureTarget; @GET @Produces(MediaType.APPLICATION_JSON) public void getLocationsWithTemperature (@Suspended final AsyncResponse async) ( long startTime = System.currentTimeMillis(); // Създаване на етап за извличане на местоположения на CompletionStage > locationCS = locationTarget.request() .rx() .get(нов GenericType >() ()); // Чрез създаване на отделен етап в етапа на местоположенията, // описан по-горе, съберете списъка с прогнози // като в един голям CompletionStage последен CompletionStage > forecastCS = locationCS.thenCompose(locations -> ( // Създаване на етап за получаване на прогнози // като CompletionStage List > forecastList = // Поточно предаване на местоположения и обработка на всяко едно // поотделно locations.stream().map(location -> ( // Създаване на стъпка, за да получите // температурите само на един град // по неговото име final CompletionStage tempCS = temperatureTarget .resolveTemplate("град", местоположение.getName()) .request() .rx() .get(Temperature.class); // След това създайте CompletableFuture, който // съдържа екземпляр на прогноза с // местоположение и стойност на температурата return CompletableFuture.completedFuture(new Forecast(location)) .thenCombine(tempCS, Forecast::setTemperature); )).collect(Collectors.toList()); // Връща крайния екземпляр на CompletableFuture, където // всички представени бъдещи обекти с възможност за завършване // са завършени return CompletableFuture.allOf(forecastList.toArray(new CompletableFuture)) .thenApply(v -> predictList.stream() .map(CompletionStage::toCompletableFuture ) .map(CompletableFuture::join) .collect(Collectors.toList())); )); // Създайте екземпляр на ServiceResponse, който // съдържа пълния списък с прогнози // заедно с времето за обработка. // Създайте неговото бъдеще и го комбинирайте с // forecastCS, за да получите прогнози // и вмъкнете в отговора на услугата CompletableFuture.completedFuture(new ServiceResponse()) .thenCombine(forecastCS, ServiceResponse::forecasts) .whenCompleteAsync((response, throwable) - > ( response.setProcessingTime(System.currentTimeMillis() - startTime); async.resume(response); )); ) )
Реактивната реализация може да изглежда сложна на пръв поглед, но след по-отблизо ще забележите, че е доста проста. В изпълнението на ForecastReactiveResource първо правя клиентско повикване към услугите за местоположение, използвайки JAX-RS Reactive Client API. Както споменах по-горе, това е допълнение за Java EE 8 и помага да се създаде реактивно повикване просто с метода rx().

Сега създавам нов етап въз основа на местоположението, за да събера списъка с прогнози. Те ще се съхраняват като списък с прогнози в един голям етап на завършване, наречен forecastCS. В крайна сметка ще създам отговор на обаждане за услуга, като използвам само прогнозCS.

Сега нека съберем прогнозите като списък от етапи на завършване, дефинирани в променлива прогнозЛист. За да създам етап на завършване за всяка прогноза, предавам данните за местоположението и след това създавам променлива tempCS, отново използвайки JAX-RS Reactive Client API, който извиква температурната услуга с името на града. Тук използвам метода resolveTemplate() за изграждане на клиента и това ми позволява да предам името на града на строителя като параметър.

Като последна стъпка от поточното предаване, правя извикване на CompletableFuture.completedFuture() , като предавам новия екземпляр на Forecast като параметър. Комбинирам това бъдеще с етапа tempCS, така че да имам температурната стойност за повторените местоположения.

Методът CompletableFuture.allOf() в листинг 11 преобразува списък от етапи на завършване в predictCS. Изпълнението на тази стъпка връща голямо завършващо бъдеще, когато всички предоставени завършващи фючърси са завършени.

Отговорът на услугата е екземпляр на класа ServiceResponse, така че създавам завършено бъдеще и след това свързвам етапа на завършване на predictCS със списъка с прогнози и изчислявам времето за реакция на услугата.

Разбира се, реактивното програмиране само принуждава страната на сървъра да се изпълнява асинхронно; клиентската страна ще блокира, докато сървърът не изпрати отговор обратно на заявителя. За да се преодолее този проблем, сървърните изпратени събития (SSE) могат да се използват за изпращане на частичен отговор веднага щом е наличен, така че температурните стойности за всяко местоположение да се изпращат на клиента една по една. Резултатът от ForecastReactiveResource ще бъде подобен на списък 12. Както е показано в изхода, времето за обработка е 515 ms, което е идеалното време за изпълнение за получаване на температурни стойности от едно място.

( "прогнози": [ ( "местоположение": ( "име": "Лондон" ), "температура": ( "скала": "Целзий", "температура": 49 ) ), ( "местоположение": ( "име ": "Истанбул"), "температура": ( "скала": "Целзий", "температура": 32 )), ( "местоположение": ( "име": "Прага"), "температура": ( "скала ": "Целзий", "температура": 45 ) ) ], "Време за обработка": 515 )
Заключение

В примерите в тази статия за първи път показах синхронен начин за получаване на прогнози с помощта на услуги за местоположение и температура. След това преминах към реактивен подход, за да имам асинхронна обработка между извикванията на услугата. Когато използвате JAX-RS Reactive Client API в Java EE 8 заедно с класовете CompletionStage и CompletableFuture, налични в Java 8, силата на асинхронната обработка се отприщва чрез реактивно програмиране.

Реактивното програмиране е повече от просто внедряване на асинхронен модел от синхронен; също така опростява концепции като етапа на влагане. Колкото повече се използва, толкова по-лесно ще бъде управлението на сложни сценарии в паралелното програмиране.

Благодаря за вниманието. Както винаги, приветстваме вашите коментари и въпроси.

Можете да помогнете и да прехвърлите средства за развитието на сайта

Проверете информацията. Необходимо е да се провери точността на фактите и надеждността на информацията, представена в тази статия. Трябва да има обяснения на страницата за разговори ... Wikipedia

Интерактивността е понятие, което разкрива характера и степента на взаимодействие между обектите. Използва се в области: теория на информацията, компютърни науки и програмиране, телекомуникационни системи, социология, индустриален дизайн и др. В ... ... Уикипедия

Тази статия трябва да бъде уикифицирана. Моля, оформете го според правилата за форматиране на статии. Този термин има други значения, вижте Електромаш (значения) ... Уикипедия

чужди психотерапевтични техники- ДЪЛБОКИ ТЕХНИКИ Активна психотерапия (Fromm Reichmann). Анализ на битието (Бинсвангер). Анализ на съдбата (Сонди). Анализ на характера (В. Райх). Анализ I (H. Kohut, E. Erickson). Аналитична игрова терапия (М. Клайн). Семейна аналитична терапия (Рихтер).… … Голяма психологическа енциклопедия

Книги

  • Реактивно програмиране на C++. Проектиране на паралелни и асинхронни приложения, Pai Praseed, Abraham Peter. Проектиране на паралелни и асинхронни приложения с помощта на библиотеката RxCpp и модерен C ++ 17 Поддържани инструменти за паралелно програмиране Съвместно...
  • , Нуркевич Т., Кристенсен Б.. В тези дни, когато програмите са асинхронни и бързата реакция е най-важното свойство, реактивното програмиране ще помогне да се напише по-надежден, по-добре мащабируем и по-бърз код.…
  • Реактивно програмиране с RxJava, Томас Нуркевич, Бен Кристенсен. В наши дни, когато програмите са асинхронни и бързата реакция е най-важното свойство, реактивното програмиране ще ви помогне да пишете по-надежден, по-добре мащабируем и по-бърз код.…

Принципите на реактивното програмиране не са нови и могат да бъдат проследени до основополагащата работа на Джим Грей и Пат Хеланд върху тандемната система през 70-те и 80-те години.

Тези хора бяха много по-напред от времето си. Едва през последните 5-10 години технологичната индустрия беше принудена да преразгледа съществуващите „най-добри практики“ за развитието на корпоративната система. Тя се е научила да прилага знания за реактивните принципи на днешния свят на многоядрени и облачни изчисления.

Основата на реактивната система е предаването на съобщения, което създава времева граница между компонентите, позволява им да бъдат отделени във времето с помощта на паралелизъм и пространство, което разпределя натоварването и осигурява мобилност. Това отделяне е изискване за пълна изолация между компонентите и формира основата както за стабилността, така и за устойчивостта на системите.

Основи на реактивното програмиране

Това програмиране се фокусира върху потока от информация и разпространението на промените в данните. При използване на езици за програмиране е лесно да се разделят статични и динамични потоци, докато основният модел автоматично ще разпространява промените през всички потоци от данни. С прости думи, при Rx програмиране, излъчено от един компонент и основната структура, предоставена от Rx библиотеките, ще разпространи тези промени към друг компонент, регистриран да получава тези промени. Реактивното програмиране Rx се състои от три ключови точки.

Основните функции на компонентите:

  1. Наблюдаваните не са нищо друго освен потоци от данни. Наблюдаваното пакетира данни, които могат да се предават от един поток към друг. Те основно излъчват данни периодично или само веднъж в жизнения си цикъл въз основа на конфигурации. Има различни оператори, които могат да помогнат на наблюдателя да изпрати някои специфични данни въз основа на определени събития.
  2. Наблюдателите консумират потока от данни, излъчван от наблюдаемото. Наблюдателите се абонират, използвайки метода за реактивно програмиране subscribeOn(), за да получават данни, предавани към наблюдаеми. Всеки път, когато наблюдаем подава данни, всички регистрирани наблюдатели получават данните в обратното извикване onNext(). Тук те могат да извършват различни операции, като анализиране на JSON отговор или актуализиране на потребителския интерфейс. Ако има грешка, причинена от наблюдаемото, наблюдателят ще го получи в onError().
  3. Schedulers (schedule) е компонент в Rx, който казва на наблюдателите и наблюдателите на коя нишка трябва да се изпълняват. Можете да използвате метода observOn(), за да кажете на наблюдателите коя нишка трябва да наблюдават. Алтернативно, schedOn() може да се използва, за да се каже на наблюдаемата в коя нишка трябва да се изпълняват.

При реактивно програмиране, използвайки основни нишки по подразбиране на RxJava, като Schedulers.newThread(), ще се създаде нов фон. Schedulers.io() ще изпълни кода на I/O нишката.

Основните предимства на Rx са повишено използване на изчислителни ресурси на многоядрен и многопроцесорен хардуер, подобрена производителност чрез намаляване на точките и подобрена производителност чрез намаляване на точките за сериализация, съгласно закона на Амдал и закона на Гюнтер за универсалната мащабируемост.

Второто предимство е високата производителност за разработчиците, тъй като традиционните програмни парадигми се борят да осигурят прост и поддържаем подход за справяне с асинхронно и неблокиращо изчисление и IO. Функционалното реактивно програмиране се справя с тези задачи, защото обикновено елиминира необходимостта от изрична координация между активните компоненти.

Когато се появи Rx, се създава процесът на създаване на компоненти и съставянето на работни потоци. За да се възползвате напълно от асинхронното изпълнение, активирането на обратното налягане е от решаващо значение, за да се избегне прекомерна употреба или по-скоро неограничена консумация на ресурси. За да се осигури стабилно състояние по отношение на потока от данни, базираното на натоварването обратно налягане изпраща търсене нагоре по веригата и получава съобщения.

И така, основните предимства на системата са:

  1. Повишена производителност - благодарение на способността за бързо и последователно обработване на огромни количества данни.
  2. Подобрен UX - поради факта, че приложението е по-отзивчиво към потребителя.
  3. Опростени модификации и актуализации - благодарение на по-четливия и по-лесен за прогнозиране код.

Но въпреки че реактивното програмиране е много полезно нещо при изграждането на модерен софтуер, за да мислите за система на по-високо ниво, трябва да използвате друг инструмент - реактивна архитектура за процеса на проектиране на реактивни системи. Освен това е важно да запомните, че има много парадигми за програмиране и Rx е само една от тях, като всеки инструмент, той не е предназначен за всички случаи на употреба.

Стабилност на реактивната система

Устойчивостта е отзивчивост към отказ и е присъщо функционално свойство на системата. Нуждае се от развитие, а не само от добавяне със задна дата към системата. Устойчивостта на реактивното програмиране с javascript надхвърля толерантността към грешки и не се дължи на влошаване, но в случай на повреда може напълно да се коригира.

Това изисква изолиране на компоненти и ограничаване на грешките, за да се избегнат откази, разпространяващи се към съседни компоненти, което може да доведе до каскадни сценарии за катастрофални откази. По този начин ключът към изграждането на устойчиви системи е, че те могат да бъдат характеризирани като съобщения, изпратени до други компоненти, които действат като надзорници и се управляват от защитен контекст извън повредения компонент.

Тук, тъй като се управляват от съобщения, тези съоръжения се отдалечават от тясно свързани, крехки, дълбоко вложени синхронни вериги за повиквания, които най-често се игнорират. Идеята е да се отдели обработката на повреди от веригата на повикванията, например чрез освобождаване на клиента от отговорността за обработка на грешки на сървъра.

Тъй като повечето системи по своята същност са сложни, един от най-важните аспекти е да се гарантира, че системната архитектура гарантира, че има минимално влошаване на производителността както при разработка, така и при поддръжка на компоненти, като в същото време се намалява случайната сложност до минимум. Това е важно, защото по време на жизнения цикъл на една система, ако тя не е правилно проектирана, ще става все по-трудно да я поддържате работеща и ще са необходими повече време и усилия за разбиране, за да се изолират и коригират проблемите.

Реактивните системи представляват най-продуктивната системна архитектура в контекста на многоядрени, облачни и мобилни архитектури:

  1. Изолирането на повреди предлага прегради между компонентите, предотвратявайки каскадни повреди и ограничавайки обхвата и сериозността на повредите.
  2. Йерархиите на супервайзорите предлагат множество нива на защита, съчетани с възможности за самовъзстановяване, което елиминира много временни неуспехи на всякакви оперативни разходи за разследване.
  3. Пропускането на съобщения и прозрачността на местоположението ви позволяват да деактивирате и замените компоненти, без да се засяга изживяването на крайния потребител. Това намалява разходите за повреди, тяхната относителна спешност и ресурсите, необходими за диагностицирането и отстраняването им.
  4. Репликацията намалява риска от загуба на данни и намалява влиянието на повредата върху наличността на извличане и съхранение на информация.
  5. Еластичността позволява ресурсите да бъдат запазени при колебания в използването, минимизирайки оперативните разходи при ниско натоварване и риска от повреда или спешна инвестиция в скалируемост при увеличаване на натоварването.

Уеб приложенията могат да се възползват значително от Rx стила на разработка, който ви позволява да композирате работни потоци заявка-отговор, които включват разклоняване в извиквания на услуги, асинхронно извличане на ресурси и съставяне на отговор и последващо сортиране за клиента. Съвсем наскоро събитията от типа push-to-server и уеб сокетите стават все по-често срещани в практиката и извършването на това в мащаб изисква ефективен начин за съхраняване на много отворени връзки и където IO не блокира.

Има инструменти за това, като потоци и фючърси, които правят неблокиращите и асинхронните преобразувания лесни и ги изпращат до клиентите. Реактивно програмиране на слоя за достъп до данни - Актуализира и прави заявки за данни в ефективен ресурс, за предпочитане използвайки SQL или NoSQL бази данни с асинхронни драйвери.

Уеб приложенията също се възползват от разработването на реактивна система за неща като разпределено кеширане, съгласуваност на данните и известия с множество възли. Традиционните уеб приложения обикновено използват стоящи възли. Но веднага щом програмистите започнат да използват Server-Sent-Events (SSE) и WebSockets, тези възли стават оперативни, защото като минимум поддържат състоянието на клиентската връзка и съответно им се изпращат насочени известия. Това изисква разработването на реактивна система, тъй като това е област, в която адресирането на получателите чрез съобщения е важно.

Същността на Java реактивното програмиране

Не е задължително да се използва Rx в реактивни системи. Тъй като Rx програмирането и реактивните системи не са едно и също нещо. Въпреки че често се използват взаимозаменяемо, те не са точни синоними и отразяват различни неща. Системите представляват следващото ниво на "реактивност". Това ниво предполага специфични дизайнерски и архитектурни решения, които ви позволяват да създавате стабилни и гъвкави приложения.

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

В Java, наследството на старото обектно-ориентирано програмиране, асинхронността може да стане наистина сложна и да направи кода труден за разбиране и поддръжка. По този начин Rx е особено полезен за тази "чисто" обектно-ориентирана среда, защото улеснява работата с асинхронни нишки.

С последните си издания, започвайки с Java 8, самата Java направи някои опити за внедряване на естествена реактивност, но тези опити не са много популярни сред разработчиците днес. Има обаче някои живи и редовно актуализирани реализации на трети страни за реактивно програмиране на Java, които могат да спасят положението и затова са особено ценени от разработчиците на Java.

В едно типично приложение е обичайно многократно да се изпълняват някои реактивни програмни операции с помощта на RxJava, така че трябва да сравните скоростта, CPU и използването на паметта със същите операции, които са били реализирани както с Kotlin съпрограми, така и с RxJava. Това е първоначален тест за ефективност.

Всеки път, когато се прилага нов инструмент, който ще се използва широко в целия код, е важно да се разбере дали това ще повлияе на цялостната производителност на приложението, преди да решите дали си струва да го използвате. Практиката на използване дава краткия отговор: в повечето случаи потребителите трябва да обмислят замяната на RxJava със съпрограми Kotlin, особено в Android.

Реактивното програмиране с помощта на RxJava все още може да се използва в ограничен брой случаи и в тези случаи както RxJava, така и съпрограммите могат да се смесват.

Прости причини:

  1. Те осигуряват много повече гъвкавост от обикновения Rx.
  2. Осигурява богат набор от оператори на колекции, които ще изглеждат по същия начин като операторите на RxJava.
  3. Реактивното програмиране на Kotlin може да взаимодейства, когато е необходимо, с помощта на rxjava.
  4. Те са много леки и ефективни предвид по-високото използване на процесора за събиране на боклук от всички обекти, създадени от RxJava.

Реактивни разширения

Reactive Extensions (ReactiveX или RX) е библиотека, която следва принципите на Rx, т.е. композиране на асинхронни програми и програми, базирани на събития, използвайки видима последователност. Тези библиотеки предоставят много интерфейси и методи, които помагат на разработчиците да пишат чист и прост код.

Реактивните разширения се предлагат на няколко езика. Програмистите се интересуват особено от RxJava и RxAndroid, тъй като android е най-фокусираната област.

Реактивното програмиране с помощта на RxJava е реализация на Java Reactive Extension от Netflix. По принцип това е библиотека, която съставя асинхронни събития, следвайки модела на наблюдателя.

Възможно е да се създаде асинхронен трафик, да се трансформира и консумира от наблюдателя в различни потоци от данни. Библиотеката предлага широк набор от невероятни оператори като map, join и filter, които могат да бъдат приложени към потока от данни. Когато програмистът започне да използва действителни примери за код, той ще научи повече за операторите и преобразуванията.

Многопоточност в приложенията за Android

Android" class="if uuid-2938324" src="/misc/i/gallery/73564/2938324.jpg" />

Реактивното програмиране на Android (RxAndroid) е специфично за платформата Android с няколко добавени класа върху RxJava. По-конкретно, програмистите за планиране са въведени в RxAndroid (AndroidSchedulers.mainThread()), което играе важна роля в поддържането на концепцията за многопоточност в приложенията за Android.

Освен всичко друго, експертите съветват да използвате само библиотеката RxJava. Дори благодарение на големия брой планировчици, използвани в програмирането за Android.

По-долу е даден списък на планировчиците и тяхното резюме:

  1. Schedulers.io() – Използва се за извършване на неинтензивни операции като мрежови повиквания, четене на диск/файл, операции с бази данни и който поддържа набор от нишки.
  2. AndroidSchedulers.mainThread() - Осигурява достъп до основната нишка/UI тема. Обикновено операциите се извършват в тази нишка, като например актуализиране на потребителския интерфейс, взаимодействие с потребителя. Експертите съветват потребителите да не извършват никакви интензивни операции върху този поток, тъй като това може да доведе до срив на приложението или ANR диалог.
  3. Schedulers.newThread() - Използвайки това, ще се създава нова нишка всеки път, когато се планира задача. Обикновено се препоръчва да не се използва графикът за много дълги работни места. Нишките, създадени с newThread(), няма да бъдат използвани повторно.
  4. Schedulers.computation() - Този график може да се използва за извършване на интензивни операции на процесора, за обработка на огромни данни от центъра за реактивно програмиране, за обработка на растерни изображения. Броят на нишките, създадени с помощта на този планировчик, зависи изцяло от броя на наличните процесорни ядра.
  5. Schedulers.single() - Този планировчик ще изпълни всички задачи в следния ред, който може да се използва, когато е необходимо последователно изпълнение.
  6. Schedulers.immediate() – Този планировчик изпълнява задачата незабавно чрез синхронно блокиране на основната нишка.
  7. Schedulers.trampoline() - Изпълнява задачи в режим First In-First Out. Всички планирани задачи ще се изпълняват една след друга, ограничавайки броя на фоновите нишки до една.
  8. Schedulers.from () - позволява ви да създадете планировчик от изпълнител, ограничавайки броя на създадените нишки. Когато пулът от нишки е зает, задачите ще бъдат поставени на опашка.

Сега, след като имате добър опит в RxJava и RxAndroid, можете да преминете към някои примери на код, за да разберете по-добре концепцията. За да започнете, трябва да добавите зависимостите RxJava и RxAndroid към проектите build.gradle и да синхронизирате проекта.

Програмиране.

Наблюдателят е абониран за Observable, така че да може да започне да получава данни, като използва два метода:

  1. SubscribeOn(Schedulers.io()) - Казва на Observable да започне задача във фонова нишка.
  2. ObservOn(AndroidSchedulers.mainThread()) - Казва на наблюдателя да получава данни в нишката на Android UI.

Това е всичко, за да може програмистът да напише първата си програма за реактивно програмиране с RxJava.

Предприятията и доставчиците на междинен софтуер започнаха да използват Reactive и през 2016-2018 г. се наблюдава огромно увеличение на корпоративния интерес към приемането на тази парадигма.

Rx предлага производителност на разработчиците чрез ефективност на ресурсите на ниво компонент за вътрешна логика и трансформация на потока от данни, докато реактивните системи предлагат производителност за архитекти и DevOps чрез устойчивост и еластичност на системно ниво. Те се използват за създаване на "Cloud Native" и други широкомащабни разпределени системи. На практика книгите за реактивно програмиране на Java също се използват широко с методи, които ви позволяват да комбинирате принципите на дизайна на реактивната система.



Зареждане...
Връх