Presne tak. Toto je velmi jednoduchy a prisne specificky balicek - nesynchronizovana deque, nic dalsiho (a tak by to IMHO melo v ekosystemu Golangu byt, i kdyz neni ;)
Mna az zaraza, ze pre ake zakladne struktury treba v Go samostatnu kniznicu... to sme ako v javascripte.
Je to tak. Sice v balicku container je par pokusu - heap a ring, taky obousmerne vazany seznam, ale to je vsechno. Navic zrovna ta implementace je dost nizkourovnova, tedy nic pro bezne pouziti. Takze hodne SW proste stoji na rezech a mapach (podle toho vypada casova slozitost - divam se i na nase projekty :/)
Ted s Go 1.18 a moznosti generickych typu se to lepsi, protoze jdou vytvorit plnohodnotne datove kontejnery - viz tento minibalicek nebo Go18DS.
Ale proc? Rob Pike docela obsirne mluvi o tom, proc Go vypada tak, jak vypada (a dost s nim souhlasim), ale zrovna std knihovny moc neprobira, co tak jsem videl jeho prednasky.
Ony ty řezy jsou docela promyšlené, díky kapacitě se s nimi dají dělat zajímavé věci (efektivně), například různé fronty. Je to podobné tomu, jak se kanály dají použít například k implementaci semaforů. Ale intuitivní to moc není.
Jo, řezy i mapy jsou fajn, ale člověk musí tušit, jak to funguje interně.
Zrovna letos jsem řešil jeden performance problém s mapami. Ony sice teoreticky mají krásnou časovou složitost, ale interně jsou mapy hodně složité a musel jsem se pohrabat v assembleru a zjistit, proč máme hrozné memory peaky a celý start servicy se prodloužil o cca 20 sekund (což už je dost).
Tedy nakonec to byla trivka - developer mi neuváděl kapacitu mapy při její konstrukci i když počet prvků byl známý. Potom interní realokace bloků to naprosto zabily; byla z toho taková Java servica s 200MB paměti na pod a ne 50MB :-)
Jo, kapacita u řezů a map je super věc, když ji člověk nezapomene použít :) Myslím, že to je prakticky všude, Rust nebo Julia to mají úplně stejně.
jj. Trošku paradoxně ta neuvedená kapacita (resp. reallocy) bolí víc v Go, protože se do mapy/řezu přímo ukládají hodnoty a ne reference. Třeba v Javě se to projeví později, protože se všude používají reference (resp. přesněji - halda je v Javě tak přeplněná referencemi, že rozdíl není tak velkej :-)
* my vlastně meli mapu UUIDů v řetězcové podobě, což je nějakých 36 bajtů per prvek mapy. A u milionů položek už realloc položí každej stroj :-)
To pak to kopírování nemuselo být tak hrozné :)
Ono vůbec Go má svoje špecifiká. Ale když člověk zná jeho vnitřnosti, dá se v tom psát efektivně (viz takové ty různé zero allocation knihovny).
jo no, pořád je to 4x víc, než reference v JVM, když se použije compressed oops (a většinou to postačuje, ostatně kdo překračuje 32GB per proces?). A to tedy nejsem fanoušek JVM, toho jsem si už užil dost a dost :p
Dnešní Javu neznám, naposledy jsem v ní psal někdy okolo roku 2005. Ale faktem je, že překopírovat mapu je o dost složitější než řez.
Neukázalo se compressed oops jako slepá cesta? A nezmizela dokonce z novějších JVM? (možná se pletu, bo jsme později přešli na aarch64, které to nepodporují z principu)
I tak - předpokládám, že se nekopíruje jen řetězec, ale musí se vytvořit nový node, který obsahuje typicky hash code, referenci na další, samotný objekt či referenci a k tomu samozřejmě hlavičku. Takže ve výsledku bude samotná "hodnota" tvořit jen 20-30%, což je zanedbatelný rozdíl. To zpoždění 20 s mi smysl moc nedává, i těch 200 MB na map bude otázkou milisekund - pokud nemá Go něco drasticky jinak...?