Elixir GenServer обаждане срещу актьорски състав

GenServer.call не е само за връщане на отговор

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

Донякъде свързани с това са понятията за участие и извикване в GenServer. На пръв поглед при изграждането на система с основи на OTP е лесно да се мисли следното:

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

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

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

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

TLDR; Решението между гласове и разговори е повече от просто определяне дали се нуждаете от отговор. Когато се съмнявате, използвайте обаждане.

Да се ​​надяваме, че глупавата аналогия отдолу хвърля малко светлина по този въпрос.

Това е Боб. Боб е GenServer.

Боб наистина харесва две неща в своя малък свят.

Той с удоволствие прави занимания и проверява пощенската си кутия за нови задължения.

Един дълг Боб наистина е добър да прави чинии.

Здравейте. Казвам се Боб и обичам домакинските работи!

Това е Мери. Мери мрази да се занимава.

Тя наистина не обича да прави ястия.

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

Не обичам да правя занимания. Особено ястия!

Всеки път, когато Мери се нуждае от готови ястия, тя изпраща съобщение до пощенската кутия за служебни услуги на Боб.

Тя ще изпрати съобщението до Боб, използвайки обаждане, с което Боб знае, че Мери очаква съобщение, когато работата е свършена.

Мери сега ще седне и ще чака отговора на Боб. Мери не може да направи нищо друго, докато тази чиния не се върне чиста.

GenServer.call (bob, {: do_dishes,: plate})

Когато Боб получава съобщението, което му казва да мие чиния, той започва веднага.

До този момент той стоеше на пощенската си кутия и само чакаше възможността да измие някои съдове.

Той наистина го обича толкова много.

Няма да прави нищо друго, докато не бъде направено измиване.

Харесва ми да съм съсредоточена.

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

Единственият реален начин Боб да разшири работата си е да наеме повече хора като него. Но засега той добре се справя с натоварването.

В момента Мери е единственият му клиент.

Аз съм само обикновен пещерняк. Тук няма многозадачни задачи.

Когато Боб довърши работата за Мери, той ще изпрати съобщение до пощенската й кутия, в което ще й каже, че е свършено. Това е така, защото тя изпрати съобщението, използвайки обаждане. Това казва на Боб да отговори на Мери.

Когато Мери знае, че ястието е готово, може да продължи с деня си. Обаждането пречи на Мери да прави каквото и да било друго, включително да добави още работа към Боб.

Едно по-малко ястие за миене. Радвам се, че Боб е толкова добър в ястията. Но не съм истински продуктивен, докато Боб ги мие.

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

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

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

Това позволява на Мери да премине към други неща, докато Боб прави чиниите.

Актьорският състав не е блокиращ само за Мери. Боб все още не може да бъде прекъснат, докато мие чинии.

GenServer.cast (bob, {: do_dishes,: fork})

Боб все още получава съобщенията в пощенската си кутия по същия начин, както преди, когато тя използва актьорски състав, но той не знае да си прави труда да казва на Мери, че ястието е чисто всеки път. Той просто отива до пощенската си кутия, когато свърши, и гледа дали има още чинии, които трябва да се измият.

Мери се доверява на Боб само за да го направи и това работи чудесно за известно време.

Не мога да взема достатъчно от тези ястия!

Непознат за Мери, Боб успя да се измъкне малко и приятелите му предложиха да вземе допълнителни клиенти за своята услуга.

Всички нови клиенти изпращат допирни съобщения с помощта на гласове, а не с повикване, те не искат да чакат, докато Боб свърши точно както Мери не.

Единственият проблем е, че Боб е приел повече работа, отколкото може да се справи в даден ден, а натовареността не показва никакви признаци за отпускане.

Мери няма представа, че Боб се бори. Тя се доверява на Боб. Мери продължава да изпраща дълги съобщения до Боб.

О, човече. Имам 500 чинии за пране и те просто продължават да идват.

След ден-два Мери започва да се дразни, че Боб още не е довършил всичките си ястия. Тя планира вечеря с приятели и няма вилици.

(Стандартен GenServer.call би изчакал до момента, но просто се преструвайте с мен)

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

Мери спира да изпраща домакински дела на Боб от безсилие.

Предполагам, че засега ще си мия чиниите.

Няколко дни по-късно Боб най-накрая се захваща с натовареността.

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

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

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

Сега имам ограничен брой чинии на опашката, за да се измия. Neat.

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

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

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

Радвам се, че Боб разреши ситуацията си. Научих се да бъда по-търпелив и отново се доверявам на Боб.Аз съм като Малкият двигател, който може. Ура!