Fórum Root.cz
Hlavní témata => Vývoj => Téma založeno: xavier 03. 06. 2018, 16:26:00
-
Ahojte, potrebujem v projekte pouzit thread-safe mapu, ktorej typ hodnoty bude List.
Map<String, List<FooObject>> map = new ConcurrentHashMap<>();
Aku implementaciu listu by ste mi poradili? Nieco z guavy, alebo apache commons? Dik
-
Proč nechcete použít některou z implementací ve standardní knihovně? A počítáte s tím, že použití thread-safe listu v thread-safe mapě ještě automaticky nezaručuje thread-safe použití jako celku?
-
Doporučil bych standardní ConcurrentHashMap<K, CopyOnWriteArrayList<V>> nebo ConcurrentHashMap<K, ConcurrentLinkedQueue<V>>
Ale pozor, je to sice thread-safe (tzn. má to vždy definovaný výsledek při jakémkoliv konkurentním přístupu), ale výsledky mohou být odlišné, než budete čekat, třeba konkurentní put do té mapy se stejným klíčem vloží jen poslední vkládaný seznam, budete muset používat putIfAbsent a kontrolovat návratovou hodnotu. Bezpečná by byla konkurentní multimapa, ale neznám žádnou open source implementaci.
-
To bude jeden producer a n consumerů ?
V případě více producerů stejně musíte synchronizovat vytvoření toho listu, pokud ještě v mapě není.
V tom ohledu je boží std::map v C++, protože při použití operátoru [] automaticky vytvoří nový objekt.
Stačí definovat map<vector> mapa; a můžete jednoduše přidávat prvky jedním příkazem mapa[klíč] += prvek;
Resp. místo map a vector nějakou thread safe variantu.
-
Proč nechcete použít některou z implementací ve standardní knihovně? A počítáte s tím, že použití thread-safe listu v thread-safe mapě ještě automaticky nezaručuje thread-safe použití jako celku?
Nevyhybam sa ani tomu, kludne si necham poradit s multithreadingom nemam velke skusenosti.
-
To bude jeden producer a n consumerů ?
V případě více producerů stejně musíte synchronizovat vytvoření toho listu, pokud ještě v mapě není.
V tom ohledu je boží std::map v C++, protože při použití operátoru [] automaticky vytvoří nový objekt.
Stačí definovat map<vector> mapa; a můžete jednoduše přidávat prvky jedním příkazem mapa[klíč] += prvek;
Resp. místo map a vector nějakou thread safe variantu.
Ano, bude viac producentov
-
Kterou konkrétní implementaci vybrat záleží na tom, jakým způsobem se bude s daty pracovat. Pokud se bude z listu často paralelně číst, a jenom výjimečně do něj zapisovat, hodí se CopyOnWriteArrayList. Pokud se do listu bude běžně zapisovat, je lepší použít ConcurrentLinkedQueue nebo ConcurrentLinkedDequeue.
Celou mapu byste pak měl zapouzdřit do vlastního objektu, který bude mít např. metodu pro přidání položky a interně zavolá computeIfAbsent pro vytvoření listu, pokud ještě neexistuje, a pak do listu přidá hodnotu. Pokud je cílem multimapa, tj. mapa, která může mít pro jeden klíč víc hodnot, a stačí tedy tento slabší přístup k zamykání. Pokud by byl potřeba výhradní přístup k dané dvojici klíč:seznam, bylo by potřeba použít metodu compute.
-
Celou mapu byste pak měl zapouzdřit do vlastního objektu, který bude mít např. metodu pro přidání položky a interně zavolá computeIfAbsent pro vytvoření listu, pokud ještě neexistuje, a pak do listu přidá hodnotu.
Nemozem uz priamove volat computeIfAbsent ja v danej triede namiesto obalovania dalsim objektom?
Kterou konkrétní implementaci vybrat záleží na tom, jakým způsobem se bude s daty pracovat.
S datami sa bude pracovat nasledovne:
Uzivatel A spusti aplikaciu, cim sa vytvori zaznam, kde key bude nejake id uzivatela, a nejake metada sa ulozia do Listu. Problem vsak je, ak otvori danu aplikaciu ten isty uzivatel na novej karte, v novom okne, casom mozno pribudne iny typ aplikacie, takze uzivatel bude prihlaseny na viacerych miestach naraz, co opat vyvola ulozenie metadat na zaklade id uzivatela do mapy. Preto metadata treba ukladat do kolekcie.
Taktiez moze nastat situacia, kedy uzivatel B, spusti nejaku akciu, ktora potrebuje metada uzivatela A, ta akcia pouzije vsetky metada priradene ku klucu uzivatela A, v iteracii nad kazdym zaznamom vykona nejaku operaciu, a nasledne sa z mapy odmaze kluc aj s metadatami uzivatela A.
Trosku som sa vam pokusil objasnit pre aku pracu potrebujem dany List, je pre tento pripad vhodny spominany CopyOnWriteArrayList alebo siahnut po niecom inom ?
-
Nemozem uz priamove volat computeIfAbsent ja v danej triede namiesto obalovania dalsim objektom?
Můžete, ale pak musíte zajistit, že se prvky do mapy budou vkládat vždy správným voláním computeIfAbsent, nikdo nikdy nezavolá třeba put nebo jinou metodu pro přidání prvku do mapy. Než to hlídat na všech místech, kde by se to mohlo použít, je lepší tu mapu zapouzdřit do vlastního objektu, ze kterého se vystaví jenom metoda pro přidání hodnoty do mapy, a ta metoda už si sama zajistí, aby to přidání proběhlo správně. To je přesně důvod, proč se používá OOP.
S datami sa bude pracovat nasledovne:
Uzivatel A spusti aplikaciu, cim sa vytvori zaznam, kde key bude nejake id uzivatela, a nejake metada sa ulozia do Listu. Problem vsak je, ak otvori danu aplikaciu ten isty uzivatel na novej karte, v novom okne, casom mozno pribudne iny typ aplikacie, takze uzivatel bude prihlaseny na viacerych miestach naraz, co opat vyvola ulozenie metadat na zaklade id uzivatela do mapy. Preto metadata treba ukladat do kolekcie.
Taktiez moze nastat situacia, kedy uzivatel B, spusti nejaku akciu, ktora potrebuje metada uzivatela A, ta akcia pouzije vsetky metada priradene ku klucu uzivatela A, v iteracii nad kazdym zaznamom vykona nejaku operaciu, a nasledne sa z mapy odmaze kluc aj s metadatami uzivatela A.
Používat na tohle list mi tedy připadá dost divoké. Spíš bych do té mapy dával vlastní objekt představující přihlášeného uživatele, který bude poskytovat vlastní služby – vyhledání metadat pro danou aplikaci, odhlášení od aplikace apod. Protože třeba to procházení listu není atomická operace, a když k tomu budete přistupovat z více vláken, může se vám stát, že z jednoho vlákna ten prvek z listu smažete, ale v druhém vlákně ten prvek třeba budete modifikovat. List se tím nepoškodí a nakonec z něj ten prvek bude smazán, ale je otázka, zda je správné chování aplikace, která jeden záznam zároveň mění i maže.
Trosku som sa vam pokusil objasnit pre aku pracu potrebujem dany List, je pre tento pripad vhodny spominany CopyOnWriteArrayList alebo siahnut po niecom inom ?
To pořád závisí na poměru počtu zápisů k počtu čtení těch listů a třeba také na jejich velikosti. Což z toho vašeho popisu není patrné. Ale podle toho, jak jste to popsal, bych tam vůbec nedával list.
-
To pořád závisí na poměru počtu zápisů k počtu čtení těch listů a třeba také na jejich velikosti. Což z toho vašeho popisu není patrné. Ale podle toho, jak jste to popsal, bych tam vůbec nedával list.
Pocet zapisov by nemal byt velky, teda kazdemu klucu bude priradeny 1 zaznam, no ako som spominal problem je, ak uzivatel otvori aplikaciu v novej karte, alebo okne. Vtedy pod dany kluc v mape pribudne novy zaznam. Bohuzial nemam napad ako to spravit inac. Data ulozene v liste maju predstavuju asynchronne requesty uzivatelskych aplikacii, teda tymto ulozenym requestom sa nastavuje response, a nasledne je vystup vrateny aplikacii.
-
Rovněž doporučuji v první řadě zapouzdřit na úrovni "musí to umět operace X, Y, Z". To vám umožní vyzkoušet různé implementace.
-
Rovněž doporučuji v první řadě zapouzdřit na úrovni "musí to umět operace X, Y, Z". To vám umožní vyzkoušet různé implementace.
ano, zapuzdrenie urcite zvazim, ale aj tak sa zrejme nevyhnem pouzitiu nejakeho Listu
-
Data ulozene v liste maju predstavuju asynchronne requesty uzivatelskych aplikacii, teda tymto ulozenym requestom sa nastavuje response, a nasledne je vystup vrateny aplikacii.
Pořád nechápu, proč by ty requesty měly být uložené zrovna v listu. Co s těmi requesty budete dělat? Jak vznikne response k danému requestu?
-
Data ulozene v liste maju predstavuju asynchronne requesty uzivatelskych aplikacii, teda tymto ulozenym requestom sa nastavuje response, a nasledne je vystup vrateny aplikacii.
Pořád nechápu, proč by ty requesty měly být uložené zrovna v listu. Co s těmi requesty budete dělat? Jak vznikne response k danému requestu?
Vyuziva sa trieda zo springu deferred result, ktora zabezpeci to, aby dany objekt bol vrateny ako response az ked sa mu nastavi result. Tym ze tieto objekty drzim v kolekcii, mozem im nastavit result kedy to je potrebne, a vtedy je vysledok vrateny uzivatelovi.
-
Vyuziva sa trieda zo springu deferred result, ktora zabezpeci to, aby dany objekt bol vrateny ako response az ked sa mu nastavi result. Tym ze tieto objekty drzim v kolekcii, mozem im nastavit result kedy to je potrebne, a vtedy je vysledok vrateny uzivatelovi.
To ale pořád není důvod držet requesty v kolekci. Přece nějak zjistíte, že máte co uživateli vrátit – buď na to čekáte, tak můžete mít ten deferred result uložený u toho čekání, nebo ty odpovědi chodí nějak úplně nezávisle (např. na chatu – „pošli zprávu uživateli XY“), ovšem pak zase musíte umět identifikovat, kam se má poslat ta odpověď, a hodila by se spíš mapa, kde by byl klíč ten identifikátor a hodnota ten response. Netvrdím, že nemůže být případ, kde je vhodné použít list, ale nic moc takového mne nenapadá. Snad jen kdybyste chtěl uživateli zobrazit frontu jeho požadavků, jak postupně přicházely, nebo chtěl postupně v pořadí zpracovat všechny požadavky uživatele. Ale to neodpovídá tomu deferred result.
-
Vyuziva sa trieda zo springu deferred result, ktora zabezpeci to, aby dany objekt bol vrateny ako response az ked sa mu nastavi result. Tym ze tieto objekty drzim v kolekcii, mozem im nastavit result kedy to je potrebne, a vtedy je vysledok vrateny uzivatelovi.
To ale pořád není důvod držet requesty v kolekci. Přece nějak zjistíte, že máte co uživateli vrátit – buď na to čekáte, tak můžete mít ten deferred result uložený u toho čekání, nebo ty odpovědi chodí nějak úplně nezávisle (např. na chatu – „pošli zprávu uživateli XY“), ovšem pak zase musíte umět identifikovat, kam se má poslat ta odpověď, a hodila by se spíš mapa, kde by byl klíč ten identifikátor a hodnota ten response. Netvrdím, že nemůže být případ, kde je vhodné použít list, ale nic moc takového mne nenapadá. Snad jen kdybyste chtěl uživateli zobrazit frontu jeho požadavků, jak postupně přicházely, nebo chtěl postupně v pořadí zpracovat všechny požadavky uživatele. Ale to neodpovídá tomu deferred result.
Len aby sme sa spravne pochopili, tymi requestmi myslim deferred result objekty. ak uzivatel posle poziadavok na data, vytvori sa pre daneho uzivatela deferred result a ulzi sa do kolekcie az kym nie su pre neho nove data. Ako nahle su, tak sa deferred result objektu nasetuju dane data a ten sa potom vrati uzivatelovi ktory sa na ne poptaval. Deferred result sa potom zmaze pre daneho uzivatela z mapy.
-
Len aby sme sa spravne pochopili, tymi requestmi myslim deferred result objekty. ak uzivatel posle poziadavok na data, vytvori sa pre daneho uzivatela deferred result a ulzi sa do kolekcie az kym nie su pre neho nove data. Ako nahle su, tak sa deferred result objektu nasetuju dane data a ten sa potom vrati uzivatelovi ktory sa na ne poptaval. Deferred result sa potom zmaze pre daneho uzivatela z mapy.
No a jak se pozná to, že už data pro uživatele jsou? A jak budete hledat response, ke kterému ta data patří?
Jinak pokud je to asynchronní webový kontrolér, pozor na to, že tam je ta asynchronnost určená pro to, aby se zbytečně neblokovalo vlákno třeba při čekání na data z databáze nebo z nějaké webové služby, tedy pro věci, které by měly být vyřízené během pár vteřin. Z pohledu prohlížeče/klienta je to pořád synchronní komunikace, takže jakmile prohlížeč odešle poslední bajt požadavku, zapne stopky a měří timeout do prvního bajtu odpovědi – a pokud se nedočká ve stanoveném limitu, spojení resetuje a zobrazí chybu.
Pokud byste chtěl skutečně asynchronní komunikaci (např. chat), kde odpověď může přijít třeba za 5 nebo taky za 15 minut, je potřeba použít buď Server-sent events nebo WebSockets. Pro WebSockety má Spring také dobrou podporu včetně fallbacku pro staré prohlížeče, které WebSockety nepodporují.
-
No a jak se pozná to, že už data pro uživatele jsou? A jak budete hledat response, ke kterému ta data patří?
iny uzivatel odosle data na server kde je priznak prijimatela, na zaklade ktoreho su data v mape
-
No a jak se pozná to, že už data pro uživatele jsou? A jak budete hledat response, ke kterému ta data patří?
iny uzivatel odosle data na server kde je priznak prijimatela, na zaklade ktoreho su data v mape
Podle toho se vybere klíč v mapě. A položka v seznamu se vybere jak? Má to být fronta, takže vždy první položka?
Pokud se s odpovědí čeká na jiného uživatele, asynchronní requesty podle mne nejsou dobrá volba. Použil bych ty WebSokety, ty jsou na takovouhle komunikaci přesně určené. Ve Springu je nad tím podpora pro protokol STOMP, případně od Webtide existuje CometD, které lze také propojit se Springem. Obojí řeší předávání zpráv konkrétním posluchačům, takže nemusíte řešit právě to, které spojení je kterého uživatele.
-
No a jak se pozná to, že už data pro uživatele jsou? A jak budete hledat response, ke kterému ta data patří?
iny uzivatel odosle data na server kde je priznak prijimatela, na zaklade ktoreho su data v mape
Podle toho se vybere klíč v mapě. A položka v seznamu se vybere jak? Má to být fronta, takže vždy první položka?
Pokud se s odpovědí čeká na jiného uživatele, asynchronní requesty podle mne nejsou dobrá volba. Použil bych ty WebSokety, ty jsou na takovouhle komunikaci přesně určené. Ve Springu je nad tím podpora pro protokol STOMP, případně od Webtide existuje CometD, které lze také propojit se Springem. Obojí řeší předávání zpráv konkrétním posluchačům, takže nemusíte řešit právě to, které spojení je kterého uživatele.
technologicke rozhodnutia nie su v mojej kompetencii, rob to co mam nariadene od veduceho ... kazdopadne otazka nebola aku technologiu zvolit ale aku kolekciu pouzit pre dany problem
-
kazdopadne otazka nebola aku technologiu zvolit ale aku kolekciu pouzit pre dany problem
Pořád ještě nevíme, jak se z té kolekce bude číst, bez toho se opravdu nedá určit, jakou kolekci použít a zda vůbec použít kolekci.
Navíc pokud nevíte, jakou kolekci použít, měl by vám to snad říci ten vedoucí, ne…
-
Pořád ještě nevíme, jak se z té kolekce bude číst, bez toho se opravdu nedá určit, jakou kolekci použít a zda vůbec použít kolekci.
ak pridu nove data od nejakeho uzivatela, vezme sa priznak z tych dat, pozrie sa ci mapa obsahuje nejake "cakajuce" requesty, teda uzivatelov ktory cakaju na tieto data, ak ano iteraciou sa kazdemu deferred resultu v kolekcii nastavia dane data
-
ak pridu nove data od nejakeho uzivatela, vezme sa priznak z tych dat, pozrie sa ci mapa obsahuje nejake "cakajuce" requesty, teda uzivatelov ktory cakaju na tieto data, ak ano iteraciou sa kazdemu deferred resultu v kolekcii nastavia dane data
Takže se to má nastavit všem objektům pro daného uživatele a na pořadí nezáleží. A po nastavení dat se předpokládám celá kolekce smaže (respektive kvůli vícevláknovému přístupu by spíš měla naopak nejdřív vyjmout z mapy, aby už se neměnila, a pak nastavit výsledky). V tom případě by stačil Set, ale protože unikátnost je zaručená z povahy věci a není nutné ji kontrolovat, z hlediska výkonu bude asi lepší LinkedList. Buď tedy ConcurrentLinkedQueue, a nebo použít ConcurrentHashMap a její metodu compute a uvnitř už pak běžný nesynchronizovaný LinkedList – to si myslím, že bude v tomto případě nejefektivnější řešení.
-
ak pridu nove data od nejakeho uzivatela, vezme sa priznak z tych dat, pozrie sa ci mapa obsahuje nejake "cakajuce" requesty, teda uzivatelov ktory cakaju na tieto data, ak ano iteraciou sa kazdemu deferred resultu v kolekcii nastavia dane data
Takže se to má nastavit všem objektům pro daného uživatele a na pořadí nezáleží. A po nastavení dat se předpokládám celá kolekce smaže (respektive kvůli vícevláknovému přístupu by spíš měla naopak nejdřív vyjmout z mapy, aby už se neměnila, a pak nastavit výsledky). V tom případě by stačil Set, ale protože unikátnost je zaručená z povahy věci a není nutné ji kontrolovat, z hlediska výkonu bude asi lepší LinkedList. Buď tedy ConcurrentLinkedQueue, a nebo použít ConcurrentHashMap a její metodu compute a uvnitř už pak běžný nesynchronizovaný LinkedList – to si myslím, že bude v tomto případě nejefektivnější řešení.
zaznamy unikatne predsa nebudu, pretoze uzivatel moze otvorit aplikaciu v novom okne, tie data sa posielaju automaticky, cize duplicity vznikat budu, a je potreba reagovat na vsetky, nemoze sa stat, ze aplikacia zobrazi v jednom okne ine vysledky ako v tom druhom ... kazdopadne dakujem za radu, cize naozaj staci obycajny linked list nesynchronizovany? myslel som ze ak sa vyuziva multithreading musia byt synchronne aj vnorene kolekcie v mape
-
zaznamy unikatne predsa nebudu, pretoze uzivatel moze otvorit aplikaciu v novom okne, tie data sa posielaju automaticky, cize duplicity vznikat budu, a je potreba reagovat na vsetky, nemoze sa stat, ze aplikacia zobrazi v jednom okne ine vysledky ako v tom druhom
Záznamy unikátní budou, protože záznamem je asynchronní požadavek a ten vznikne pokaždé nový.
kazdopadne dakujem za radu, cize naozaj staci obycajny linked list nesynchronizovany? myslel som ze ak sa vyuziva multithreading musia byt synchronne aj vnorene kolekcie v mape
Synchronizované musí být zdroje, ke kterým se přistupuje z více vláken. A v případě ConcurrentHashMap zajistí synchronizaci metoda compute, která se pro daný klíč provádí atomicky.
-
Synchronizované musí být zdroje, ke kterým se přistupuje z více vláken
No prave, to v pripade Listu v mape bude nie? Ako som spominal ak uzivatel spusti aplikaciu na viacerych miestach zaroven, tak tie deferred resulty sa budu pridavat z viacerych vlaken.
-
Synchronizované musí být zdroje, ke kterým se přistupuje z více vláken
No prave, to v pripade Listu v mape bude nie? Ako som spominal ak uzivatel spusti aplikaciu na viacerych miestach zaroven, tak tie deferred resulty sa budu pridavat z viacerych vlaken.
Ano, ale ten přístup bude synchronizovaný přes mapu. Zapisovat se do toho listu bude pouze v rámci volání metody compute, která zajistí synchronizaci, a číst se bude až po zavolání remove na mapě, takže ten list pak bude ve vlastnictví jednoho vlákna a ostatní už k němu nebudou mít přístup.
-
Dakujem