1
Vývoj / Re:Rýchly vývoj administračného rozhrania
« kdy: 06. 01. 2020, 22:54:16 »
Ja pouzivam Vaadin. Doporucuji v kodu poctive oddelovat GUI od aplikacni logiky.
Tato sekce Vám umožňuje zobrazit všechny příspěvky tohoto uživatele. Prosím uvědomte si, že můžete vidět příspěvky pouze z oblastí Vám přístupných.
vy jste mi vysvetlil, ze lze vyvolat vyjimku chybou v programu...Nikoli, já jsem vám vysvětlil, že ConcurrentModificationException nemá nic společného s vícevláknovým přístupem. Ono je to s vlastně skoro opačně. ArrayList není bezpečné používat z více vláken bez explicitní synchronizace přístupu, a pokud se ho pokusíte používat z více vláken bez synchronizace, může se vám stát, že např. pokud budete v jednom vlákně iterovat a v druhém vlákně seznam modifikovat, výjimka ConcurrentModificationException nevypadne.
Sice jsem vám zase jen opsal to, co je napsané v JavaDocu, ale doufám, že to k něčemu bylo, ten JavaDoc si teď dostudujete a příště nebudete ArrayList a ConcurrentModificationException spojovat s více vlákny.Ne, pouze jsem nepredpokladal, ze vam ty % nebudou zrejme.Dost ubohý pokus, já si pamatuju, o čem jsem psal, a kdybych si to nepamatoval, můžu si to přečíst. Psal jsem, že vám v tom přehledu benchmarků dost podstatná kategorie chybí. Což nezamaskujete tím, že se budete pokoušet vrátit k těm, kter jste vyjmenoval, a vymýšlet si, že je nechápu.
Proc jen jsou odstupnovane..? Tak zapojte hlavu a zkuste to vymyslet, at to to nemusim vysvetlovat zcela polopaticky.Nekolikrat jste napsal, ze jste neco dokazal. Ne.Problém je v tom, že nevíte, co je to algoritmus. Algoritmus je popis řešení problému určený pro lidi – a ten já jsem napsal. Na rozdíl od vás, vy jste napsal implementaci algoritmu, v konkrétním programovacím jazyce. Z vašeho kódu není tak těžké algoritmus odvodit, ale algoritmus to není.
Pouze jste jedno poprel a druhe se snazil odiskutovat. To ale neni zadny dukaz, to je tlachani.
Zadny aloritmus k porovnani jsem od vas nevidel a zadny zrejme ani neuvidim.
Ten mnou popsaný algoritmus není nijak složitý, měl byste být schopen ten kód napsat sám. Zvlášť pokud chcete dělat jeho benchmark – udělat rozumný benchmark není nic snadného, není to jen změřit pár čísel, která nic neznamenají. Umět nějaký kód napsat je nutná podmínka toho, abyste na něj mohl udělat dobrý benchmark – protože tomu kódu musíte rozumět, musíte vědět, jaká jsou jeho slabá a silná místa. Jinak tím svým benchmarkem klidně změříte nějakou výjimečnou situaci, kde ten kód bude náhodou výjimečně efektivní nebo výjimečně neefektivní.
Třeba. Nebo to podle vás nejde?
Je zvláštní, že jste vynechal zrovna ten parametr, o kterém se celou dobu bavíme – tedy jaká je distribuce indexů určených ke smazání. Víte o tom, že třeba třídící algoritmy jsou různě efektivní v závislosti na tom, zda mají třídit náhodně seřazená data, už seřazená data, částečně seřazené data nebo data seřazená v opačném pořadí? I kdybych tu nepsal o algoritmu, který bude tím efektivnější, čím větší souvislé bloky se budou mazat, alespoň ta podobnost s řazením vás mohla trknout.
Dávno už se stalo.
val filteredIdx = toremove.stream().map(list::get).collect(Collectors.toList());
ConcurrentModificationException ale může vypadnout i v jednovláknové aplikaci. Připadá mi to jako dost základní znalost.
Vy zase předpokládáte, že co nevidíte, to neexistuje. Já jsem tady ale modifikaci vašeho algoritmu popisoval.
Já zase nevidím, že byste tu někde popisoval konkrétní benchmark. Původní dotaz byl velmi vágní, můžete vymyslet asi tak milion různých benchmarků, a každý vám vyjde jinak.
Akorát potvrzujete, že vám výpočetní složitost mnoho neříká. Nejdřív jste přišel s obecným tvrzením, že váš algoritmus je maximálně efektivní (tedy ze všech možných hledisek a ve všech možných případech), a teď to chcete dokazovat jedním benchmarkem.
Já bych to uzavřel tím, že váš algoritmus je pro potřeby tazatele dobrý, a do dalšího teoretizování o něm se raději nepouštějte.
dlouhá diskuze, zatím tu nezanělo žádné krátké řešení s vytvořením nového arraylistu. Rád bych viděl jednořádkový Java kód, který dělá to stejné co moje řešení v Kotlinu.
Zadani prece nebylo jine - zadani se zmenilo v prubehu debaty a az po mem prispevku. To je velky rozdil.Vy jste vážně hrozně naivní. Ne, to zadání nebylo jiné a nezměnilo se. Jenom bylo chybně formulované – tak, jako naprostá většina zadání.Vyraz "vyssi sptreba pameti" se vztahuje k jiz obsazene pameti.Ne, nevztahuje. Vyšší spotřeba paměti se vztahuje k jiným algoritmům ve stejném okamžiku běhu. A jiný algoritmus umí po skončení mazání mít méně obsazené paměti, než váš algoritmus.A jak jiz bylo drive zmineno, je to vlastnosti ArrayListu, ze se nasledne po operaci, ktera ma vliv na jeho velikost (zmensi se), muze zavolat metoda, ktera podkladove pole prealokuje. Ale tato operace by se nemela nemela volat vzdy, ale podle pravidel implementace ArrayListu. Vsechno toto jsem jiz drive napsal. A proc takto (podle pravidel prace ArrayListu s podkladovym polem) zmenseni podkladoveho pole neresim? Protoze resim pouze onen problem odmazani prvku z listu a povazuji problem zmenseni podkladoveho pole za marginalni - neprispivam tim prece do JDK, kde bych toto jiz resil zcela zodpovedne.Vlamujete se do otevřených dveří. Já jsem nikde nepsal, že je z tohoto pohledu váš kód špatně. Pouze jsem ukázal, že existuje paměťově efektivnější algoritmus, čímž jsem vyvrátil vaše tvrzení, že váš algoritmus je nejefektivnější možný. Mimochodem, už jenom to, že existují dva mírně odlišné algoritmy, z nichž jeden je paměťově efektivnější, ale druhý je v obecném případě správnější, svědčí o tom, že všeobecné prohlášení „nejefektivnější možný“ algoritmus je prostě nesmysl, protože – jako už jsem napsal několikrát – můžete porovnávat různé efektivity. Pokud máte problém představit si to na algoritmech, nechte si na nějaké mapě naplánovat cestu autem z bodu A do bodu B. Uvidíte, že budete mít na výběr minimálně ze dvou variant – nejrychlejší a nejkratší. Je nějaká z nich obecně nejefektivnější?Napsal jsem, ze je "maximalne efektivni". A mel jsem tim na mysli pametovou a vypocetni slozitost - tedy ta zakladni kriteria hodnoceni algoritmu.Pokud jste tím myslel, že je algoritmus efektivní z hlediska obou základních kritérií, měl jste to napsat. Ono je totiž typické, že snižování výpočetní složitosti zvyšuje paměťovou náročnost a opačně. Ostatně jako v tomto případě – výpočetní složitost můžete snížit tím, že prostě alokujete nové pole o stejné velikosti a pak zkopírujete prvky, které se nemají smazat. Ale paměťovou náročnost tím zdvojnásobíte.
Pardon, ale toho, ze jste to vyvratil, jsem si nevsiml.
Maximální efektivitu jsem vyvrátil jednoduše tak, že jsem předvedl algoritmus, který má nižší výpočetní složitost, a algoritmus, který má nižší paměťovou náročnost.Ale ne...copak native metoda je optimalizovana JITem? :-)Nemyslím si, že by ve standardu bylo uvedeno, jak přesně má být implementována metoda System.arraycopy.Presouvat bloky pole o male delce potencialne pres docasne jednorazove alokovane pole se vam zda v poradku?Potenciálně přes dočasné jednorázově alokované pole může být klidně implementováno i to vaše přiřazování. To, že je v dokumentaci napsáno „chování je ekvivalentní k“ neznamená, že to tak musí být opravdu implementováno.Tady uz pomuze pouze benchmark, jinak je to pouze akademicka debata. Tak si to prosim zkuste, jestli volani arracopy pro kopirovani prvku po jednom (resp. pro jak velke pole se to jeste vyplati a) je rychlejsi nez pure Java prirazeni prvkuVy se zkuste zamyslet nad tím, jak velká je pravděpodobnost, že při náhodném rozložení mazaných indexů se budou mazat všechny sudé nebo všechny liché prvky.
do pole.Ano. A ja jsem jiz drive take napsal, ze jsem na tomto foru reagoval proto, ze se mi to zadani libilo a zdalo se mi zajimave. Proto jsem prispel. Pokud bych vedel, ze bude stacit cyklicke volani ArrayList.remove(), tak bych se opravdu neobtezoval :-).V pořádku. Mně zase přišlo zajímavé vaše sebejisté tvrzení, že vaše řešení je maximálně efektivní. Dalo se předpokládat, že nebude problém dokázat, že existuje paměťově efektivnější nebo výpočetně efektivnější řešení – nakonec se ukázalo, že existují obě.Podstatou problemu byla prace s ArrayListem a to neni rozhrani.To, že je použitý ArrayList, málokdy bývá vytesáno do kamene. Pokud se ukáže, že ArrayList není nejvhodnější struktura, bývá možné použít jinou strukturu. Navíc ArrayList není finální třída, takže implementaci potomka nestojí nic v cestě. Když tedy chcete slovíčkařit.
Modifikovat ArrayList, ktery jsem nekam poslal, je naprosto spolehliva cesta do zadeke.
Pokud ta vzdalena strana bude mit nad arraylistem otevreny Iterator, padne to cele na hubu na ConcurrentModificationException.
Jenže se ukázalo, že zadání ve skutečnosti bylo jiné, než jste si myslel. Takže zpochybnění zadání v tomto případě vedlo k nalezení vhodného řešení – podle mne je to dobrý výsledek.
Je pozoruhodné, jak se ve vašich komentářích snoubí správný algoritmus použitý pro danou věc s absolutní neznalostí obecnějších principů. Když máte pro něco alokované větší pole, než je potřeba, vyšší spotřeba paměti tam samozřejmě je. To, že ta paměť už byla alokovaná dříve, na věci nic nemění – potřeba paměti je závislá na čase, neřeší se jenom maximum. Vašemu algoritmu možná ta nevyužitá paměť nijak nechybí, ale jiný algoritmus nebo proces by jí třeba využil – a v extrémním případě ta vámi nevyužitá paměť může způsobit třeba swapování nebo i pád aplikace, která by potřebovala alokovat další paměť, která ale není k dispozici.
Vy jste ve svém tvrzení nebyl vůbec konkrétní, právě naopak. Napsal jste, že váš algoritmus je nejefektivnější možný – tedy obecně, ve všech kritériích. Nelze napsat algoritmus, který by spotřeboval méně paměti ani algoritmus, který by spotřeboval méně procesorového času. Přitom obojí jsem vyvrátil – váš algoritmus tedy zjevně nejefektivnější možný není. Je možné, že v některých případech je nejefektivnější z hlediska procesorového času – za cenu paměťové neefektivity.
Kdybyste použil System.arraycopy(), necháváte to na JIT. V nejhorším případě udělá to, co vy jste naprogramoval ručně. Ale může to udělat i efektivněji. Vy jste ale VM nadiktoval svůj (nejpomalejší) způsob přesouvání bloků pole, s tím už JIT nic neudělá.
Jasně že to umím, vždyť je to triviální. Jako blok to přesunou jde vždy. V nejhorším případě budete přesouvat bloky o délce jedna. Což by se dalo oifovat, ale to bych považoval ze typickou předčasnou optimalizaci. Přenositelnost to v žádném případě nepoškodí.
Já už jsem vám na to odpovídal, že je naivní očekávat, že to zadání bylo takhle přesné. Ostatně jak se později ukázalo, vytvoření nového listu bylo akceptováno jako vhodné řešení – tedy to „mazání“ byl pouze laický neprogramátorský popis, bylo to jen jinak napsáno „chci, abych měl na konci list, kde nebudou prvky se zadanými indexy“. Jedna z nejdůležitějších věcí, které je potřeba se naučit ohledně analýzy problémů, je následující: To, co někdo chce, a co tvrdí, že chce, jsou obvykle dvě naprosto odlišné věci.
Proto je výhodné programovat proti rozhraním, protože pak i tu uzavřenost ArrayListu můžete snadno obejít tím, že si vytvoříte vlastní implementaci Listu, která uvnitř vymění celý ArrayList.
To je dost naivní…
Doložil jsem to už v původním příspěvku. Nelze o algoritmu tvrdit, že je „obecně efektivní“ – je velmi časté, že algoritmy efektivní na počet instrukcí nebo na strojový čas mají vyšší spotřebu paměti a naopak.
Původně mi šlo hlavně o to obecné tvrzení, ale když tak toužíte po tom vědět, proč váš algoritmus není ani maximálně efektivní vzhledem k době běhu, máte to mít. Na vašem algoritmu je výpočetně neefektivní to, že kopírujete prvky po jednom. Pokud bude v poli za sebou víc prvků, které se mají zachovat, je efektivnější zkopírovat („posunout“) celý souvislý blok najednou. Záleží na přesné implementaci funkce System.arraycopy, jestli dokáže celý blok posunout jedním směrem bez vytváření dočasného pole.
Velikost výsledného listu dopředu víme. Kopírování do nového pole by mohlo být na procesorový výkon i efektivnější, než vaše řešení – protože umožní vždy kopírovat celé souvislé bloky, nebo-li je nezávislé na efektivitě implementace System.arraycopy.
Algoritmu, ktery jsem uvedl v prispevku, je maximalne efektivniJe dost odvážné tvrdit o něčem, že je to maximálně efektivní, když neznáte přesné zadání. Váš algoritmus ponechá původní velikost podkladového pole, takže není paměťově efektivní. Kdybyste to chtěl spravit zavoláním trimToSize(), bude zase výpočetně neefektivní (nevíte, zda to zmenšení pole není zbytečné).
Metoda ArrayList.removeAll() provadi remove v cyklu, coz zvysuje vypocetni slozitost.
removeAll hlavně dělá něco jiného, než na co se ptal tazatel. Odstraňuje položky podle hodnot, on chce odstranit podle indexů.
Proč bych to měl dělat takhle, když můžu použít čitelnější postup Standy Blábola? Viz.
https://forum.root.cz/index.php?topic=21857.msg317204#msg317204
Protoze v zadani je, ze se maji z listu prvky vymazat a ne ze se ma vytvorit novy list.
Navic je tu performance.
To ale Standa Blábol taky řeší:(...)
Nebo si vyrob pomocny arraylist pro vsechny keys z keylistu a na puvodnim arraylistu zavolej removeAlll() Tehnle pristup je vhodny pokud je pocet klicu maly vzhledem k delce arraylistu.
Nepredpokladam, ze resis kazdou milisekundu, to by nebyly daove struktury tak blbe navrzene.
Proč bych to měl dělat takhle, když můžu použít čitelnější postup Standy Blábola? Viz.
https://forum.root.cz/index.php?topic=21857.msg317204#msg317204