.Net Reactive Extension предоставя на разработчиците набор от функции за реализиране на реактивен програмен модел за .Net разработчици, с цел да се направи обработката на събития по-проста и по-изразителна чрез декларативни действия. Въпреки че ключовите стълбове на реактивното скалиране са интерфейсите IObserver и IObservable, като разработчик често не е нужно да ги реализирате сами. Библиотеката поддържа вградения тип Subject<T>, който реализира интерфейси и поддържа много функции.
Темите са основата за различните теми, налични в библиотеката, а има и други теми – <T>ReplaySubject, BehaviorSubject<T> и AsyncSubject<T>. Полезно е да разберете основните разлики между тях и как да ги използвате, за да използвате библиотеката по-добре.
В тази статия ще сравним Субект<T> и неговия брат, опитвайки се да илюстрираме разликите в поведението им.
Предмет<T>
Както беше споменато по-рано, Subject<T> е основата за наличните теми, предоставяйки лесен начин за използване на библиотеката, без да се налага да имплементирате интерфейсите на IObservable<T> и<T> IObserver сами. По-долу е показана проста демонстрация на типа тема.
В горния код създадохме <T>инстанция на Subject, и тъй като той имплементира<T> IObserver и IObserverable<T>, използваме една и съща инстанция, за да се абонираме и публикуваме стойността в IObserver. Друг важен момент, който трябва да се отбележи, е как използваме претоварването на метода Subscribe, за да приемем действия като вход. Това се прави за всяка публикувана стойност, като в този случай числото се отпечатва на конзолата.
Нека се опитаме да покажем публикуваните стойности и стойностите, които IObserver (в това действие<T>) отпечатва на конзолата на следващото изображение. Това ще ни помогне лесно да сравним останалите братя и сестри и варианти.
Първият ред представлява публикуваната стойност, а вторият ред – стойността, получена от IObserver. Освен това добавихме ред, който показва в кой момент наблюдателят се абонира за потока по време на изпълнение. Тази линия е представена с вертикална пунктирна линия.
В горния код забелязахме, че наблюдателят се абонира за потока от данни преди да публикува първата стойност. Изображението показва линията Абонат, поставена преди първия елемент. Както се вижда от изходната линия, това няма ефект върху изхода (в този момент).
Но какво ако наблюдателят се абонира за данните едва след като някои стойности вече са публикувани? Има ли това влияние върху данните, получени от наблюдателите? Преди да разгледаме резултата, нека първо напишем същия код.
В горния код можем да наблюдаваме, че наблюдателят се абонира за потока от данни едва след публикуване на две стойности (1 и 2). Както може да се очаква, това ще накара наблюдателите да не получават публикувани данни преди да се обадят на абонаментния метод. Както е показано на фигурата по-долу.
Ами ако искате да прочетете всички публикувани стойности, дори ако наблюдателят се абонира късно? Тук<T> се намесва ReplaySubject.
ReplayТема<T>
ReplaySubject<T> кешира стойности и ги възпроизвежда за по-късни абонати. Това е полезно за избягване на състезателни условия. Нека променим предишния код, за да използваме<T> ReplaySubject и да видим как това влияе на това, което наблюдателят получава.
Както е показано в горния код,<T> <T>почти няма промяна в кода, освен че вече използваме ReplaySubject вместо subject. Следната диаграма илюстрира въздействието върху данните, получени от наблюдателя.
Както е показано на изображението, кешираната стойност вече се възпроизвежда на абоната, дори ако абонатът се абонира по-късно. Разбира се, тази полезна функция има своята цена. Тази реализация ще кешира всяка стойност, публикувана от абоната, което може да причини проблеми с лошата памет, когато обемът данни е значително по-голям.
Въпреки това, ReplaySubject<T> има повече от един начин да реши този проблем. За целите на този пример ще разгледаме два примера, които използват ограничения по размер и време, за да ограничат кешираната стойност.
В първия случай ще използваме размера на кеша, за да ограничим стойността му. <T>Конструкторът на ReplaySubject предоставя претоварване, което приема цяло число, представящо размера на кеш буфера (максимален брой елементи). В нашия пример нека променим кода, за да ограничим размера на кеша до 1.
Обърнете внимание как <T>използваме претоварването на конструктора в ReplaySubject, за да определим размера на кеша като 1. Това ограничава кеширането и гарантира, че само един елемент се кешира и заменя с нов веднага след публикуването му. Въздействието на промяната е показано по-долу.
Друг начин за ограничаване на кеширането е да се ограничи времето на кеширания елемент, или с други думи, да се осигури срок на годност за кеширания елемент.
Нека напишем код, за да илюстрираме този пример.
Подобно на предишния код,<T> използваме претоварването на конструктора ReplaySubject, за да зададем срока на годност на елементите в кеша. За да демонстрираме нашия случай, въведохме забавяне между освобождаването на стойности.
Тъй като са нужни цели 1200ms, преди наблюдателят да се абонира, всички елементи, които надвишават срока на годност от 1000ms, ще бъдат премахнати от кеша. В този пример това ще доведе до премахване на стойност 1 от кеша и няма да се възпроизвежда на късни абонати. Както е показано на фигурата по-долу.
<T>Има и други претоварвания за ReplaySubject, които осигуряват повече гъвкавост и фино настройват кешираните стойности, но например ще запазим двата вече описани примера.
ПоведениеСубект<T>
BehaviourSubject <T>е много подобен на<T> ReplaySubject по това, че помага за кеширане на стойности. Но има съществена разлика. BehaviourSubject<T> кешира само последната публикувана стойност. Преди да навлезем по-нататък, нека напишем малко код.
Ако BehaviorSubject<T> кешира само една стойност (която е последно известна), как се различава от ReplaySubject с размер 1<T>? Следващата диаграма ясно отразява ситуацията на горния код.
Въпреки това, това не е напълно вярно. Тук има две важни разлики, които трябва да се разберат. Първият е наличието на дефолти. Обърнете внимание, че в горния код <T>даваме стойността 0 като стандартна стойност в конструктора на BehaviourSubject. Ако няма стойност в кеша (или с други думи, данни не са публикувани преди абонирането на наблюдателя), стойността по подразбиране ще бъде върната. Това е различно от ReplaySubject, който има размер 1 <T>и няма никаква стойност. Следващият код и визуално представяне на последователността демонстрират това поведение.
Втората разлика е как се<T> държат BehaviourSubject и<T> ReplaySubject при абониране за завършена последователност. Когато се абонирате след завършване, BehaviorSubject <T> няма да има стойност, както е показано в кода по-долу.
Абонатите са гарантирано да не получават никаква стойност, тъй като абонаментите се извършват след завършване.
Въпреки <T>това, това е случаят с ReplaySubject. Няма гаранция, че наблюдателят няма да получи никакви стойности, както е показано в кода по-долу.
Както е показано в горния код, кешът е с размер 1 и дори ако абонаментът бъде извикан след завършване на повикването, кешът остава (докато не бъде изпълнено условието за изтичане), така че в този случай ще бъде получена последната публикувана стойност.
AsyncSubject<T>
<T>AsyncSubject е последният брат или сестра на Субекта, който ще разгледаме в тази <T>статия, и е много подобен на предишните два (ReplaySubject и BehaviorSubject) по това, че също кешира резултати. Но отново има значителна разлика. AsyncSubject публикува последната кеширана стойност само ако последователността е маркирана като <T> завършена (кешира само една стойност, последната стойност).
Разгледайте следния код.
Това ще генерира стойност за наблюдателя, че последователността е маркирана като последната стойност, публикувана преди завършване – стойност 4. Както е показано на фигурата по-долу.
Но какво се случва, ако пропуснем повикването, което маркира последователността като завършена? Нека коментираме в края на линията и опитаме отново.
Това не генерира никакви данни за наблюдателя, тъй като AsyncSubject<T> публикува резултатите едва след като последователността бъде маркирана като завършена.
Това е значителна разлика, която всеки, който използва AsyncSubject<T>, трябва да има предвид.
извод
Тази статия <T>демонстрира разликите между различните братя и сестри на Subject и някои от неговите вариации. Често е полезно да сте наясно с тези фини разлики, тъй като те могат да проявят различно поведение от очакваното, ако не го осъзнавате.
Оригинален линк:Входът към хиперлинк е видим.
|