Fórum Root.cz

Hlavní témata => Vývoj => Téma založeno: Golanger 21. 03. 2018, 02:33:27

Název: Velikost pole objektů v Go
Přispěvatel: Golanger 21. 03. 2018, 02:33:27
Mám proměnnou typu
Kód: [Vybrat]
[10]Worker a dávám do ní ukazatele na
Kód: [Vybrat]
type Calculon struct Velikost pole na amd64 je ale 160 bajtů, máte někdo vysvětlení, proč to není 80? (Velikost pointru by snad měla být 8 bajtů.)
Název: Re:Velikost pole objektů v Go
Přispěvatel: klokan 21. 03. 2018, 04:16:42
Neznám Go tak dalece, ale je možné, že to je podobné, jako v Rustu. Tam jsou některé ukazatele dvakrát delší, než nativní délka pointeru, protože kromě samotné adresy obsahují taky jakýsi identifikátor typu objektu (u traitů v Rustu např pointer na ekvivalent v-table). Takže když budu mít pole typu [&Krava; 10] a Krava je trait, tak to bude taky celkem 160 bajtů.

Podle tvého příkladu to vypadá, že Worker je asi interface a Calculon bude objekt, který podporuje Worker, takže to je stejná situace. Je tedy dost možné, že na to Go používá podobný mechanismus, tj. každý pointer jsou vlastně dva: jeden na samotný objekt Calculon, a jeden na vtable Worker pro Calculon.

Možná to ale tak vůbec není a některý z místních expertů na Go mě vyvede z omylu.
Název: Re:Velikost pole objektů v Go
Přispěvatel: heeeerecka 21. 03. 2018, 05:36:57
A divas se na velikost pole nebo jeho kapacitu
Název: Re:Velikost pole objektů v Go
Přispěvatel: Jester 21. 03. 2018, 07:52:42
A divas se na velikost pole nebo jeho kapacitu
Ach jo. Pole nemá kapacitu, tohle není slice.
Název: Re:Velikost pole objektů v Go
Přispěvatel: ava 21. 03. 2018, 09:03:12
Neznám Go tak dalece, ale je možné, že to je podobné, jako v Rustu. Tam jsou některé ukazatele dvakrát delší, než nativní délka pointeru, protože kromě samotné adresy obsahují taky jakýsi identifikátor typu objektu (u traitů v Rustu např pointer na ekvivalent v-table). Takže když budu mít pole typu [&Krava; 10] a Krava je trait, tak to bude taky celkem 160 bajtů.

Podle tvého příkladu to vypadá, že Worker je asi interface a Calculon bude objekt, který podporuje Worker, takže to je stejná situace. Je tedy dost možné, že na to Go používá podobný mechanismus, tj. každý pointer jsou vlastně dva: jeden na samotný objekt Calculon, a jeden na vtable Worker pro Calculon.

Možná to ale tak vůbec není a některý z místních expertů na Go mě vyvede z omylu.

Souhlasím se vším, jen drobné doplnění - ty "dvakrát větší ukazatele" se v Rustu nejmenují ukazatele ale Trait Objects. To, že syntaxe pro trait object začíná & takže se tváří jako obyčejná reference (pointer) je spíš matoucí a autoři to chtějí změnit: https://github.com/rust-lang/rfcs/blob/master/text/2113-dyn-trait-syntax.md . Ukazatel na trait object už má velikost normální:

trait T {}
println!("{}, {}", mem::size_of::<&T>(), mem::size_of::<&&T>());
16, 8

Jinak bych to napsal stejně, taky Go neznám a taky bych podezříval že tohle bude ta příčina :)
Název: Re:Velikost pole objektů v Go
Přispěvatel: Golanger 21. 03. 2018, 09:42:55
Je to kvůli polymorfismu, proměnná typu rozhraní si nese navíc odkaz na konkrétní typ. Překladač to různě agresivně optimalizuje, ale při uložení do kolekce se to projeví.
Název: Re:Velikost pole objektů v Go
Přispěvatel: . 21. 03. 2018, 09:55:20
Tohle je zvláštní, můžeš dát odkaz na kus kódu, ne jen ty dva řádky? Jak jsi měřil velikost? Odhaduji, že tam někde máš interface.

Posílám příklad: https://play.golang.org/p/csFOH8bquZG

výstup na play (64 bitů s 32 bit pointry):
Kód: [Vybrat]
amd64p32
4
8
4
4
40
40
80
40

výstup na amd64:
Kód: [Vybrat]
amd64
8
16
8
8
80
80
160
80
Název: Re:Velikost pole objektů v Go
Přispěvatel: . 21. 03. 2018, 09:57:24
Než jsem to celé dopsal, tak jsi to sám poslal. :)
Název: Re:Velikost pole objektů v Go
Přispěvatel: Jester 21. 03. 2018, 12:05:43
Jak jsi měřil velikost?
Jinak než přes unsafe.Sizeof to nejde.
Název: Re:Velikost pole objektů v Go
Přispěvatel: . 21. 03. 2018, 15:52:20
Jak jsi měřil velikost?
Jinak než přes unsafe.Sizeof to nejde.
Já bych to takhle neřešil, ale umím si představit zjišťování přes velikost alokované paměti v runtime nebo přes volbu b.ReportAllocs().
Název: Re:Velikost pole objektů v Go
Přispěvatel: klokan 22. 03. 2018, 00:18:11
Jinak bych to napsal stejně, taky Go neznám a taky bych podezříval že tohle bude ta příčina :)

Udělal jsem malý pokus: podobný příklad jako autorův jsem prohnal zkrk gccgo a podíval se do GIMPLE. Reference na Worker je skutečně struktura obsahující dva pointery: __methods a __object, neboli celkem 128 bitů.

Poučení je jasné: reference není totéž, co pointer! Člověk zvyklý na C++ si většinou myslí, že to je jenom jiná syntaxe pro stejnou konstrukci, ale v těchto novějších jazycích tomu tak už není.
Název: Re:Velikost pole objektů v Go
Přispěvatel: Jester 22. 03. 2018, 00:59:29
Jinak bych to napsal stejně, taky Go neznám a taky bych podezříval že tohle bude ta příčina :)

Udělal jsem malý pokus: podobný příklad jako autorův jsem prohnal zkrk gccgo a podíval se do GIMPLE. Reference na Worker je skutečně struktura obsahující dva pointery: __methods a __object, neboli celkem 128 bitů.

Poučení je jasné: reference není totéž, co pointer! Člověk zvyklý na C++ si většinou myslí, že to je jenom jiná syntaxe pro stejnou konstrukci, ale v těchto novějších jazycích tomu tak už není.
To už nejsou reference, tady jde o rozdíl mezi konkrétními typy a rozhraními (což je dynamický odkaz umožňující kachní polymorfismus).
Název: Re:Velikost pole objektů v Go
Přispěvatel: klokan 22. 03. 2018, 02:53:50
To už nejsou reference, tady jde o rozdíl mezi konkrétními typy a rozhraními (což je dynamický odkaz umožňující kachní polymorfismus).

Právě, že to jsou pravé reference, tj. neprůhledné proměnné zprostředkovávající přístup k určitému objektu určitou formou a za určitých podmínek. V tom se blíží definici kapabilit, na rozdíl od pointeru, který je vždycky jenom nativní strojové slovo udávající jedinou adresu v paměti. Kachní polymorfismus je jedním ze scénářů, kde tenhle rozdíl vykrystalizuje, ale jsou i jiné, např. slices (kde reference určuje adresu a velikost). V C++ jsou reference vždycky jenom obyčejné pointery, zatímco např. v Javě pointery nejsou vůbec.
Název: Re:Velikost pole objektů v Go
Přispěvatel: Jester 22. 03. 2018, 03:02:45
To už nejsou reference, tady jde o rozdíl mezi konkrétními typy a rozhraními (což je dynamický odkaz umožňující kachní polymorfismus).
Právě, že to jsou pravé reference, tj. neprůhledné proměnné zprostředkovávající přístup k určitému objektu určitou formou a za určitých podmínek. V tom se blíží definici kapabilit, na rozdíl od pointeru, který je vždycky jenom nativní strojové slovo udávající jedinou adresu v paměti. Kachní polymorfismus je jedním ze scénářů, kde tenhle rozdíl vykrystalizuje, ale jsou i jiné, např. slices (kde reference určuje adresu a velikost). V C++ jsou reference vždycky jenom obyčejné pointery, zatímco např. v Javě pointery nejsou vůbec.
Tak tuhle terminologii neznám, ale budiž, vím, o co jde. Každopádně to má Go implementačně dobře vyřešené.
Název: Re:Velikost pole objektů v Go
Přispěvatel: klokan 22. 03. 2018, 05:01:31
Tak tuhle terminologii neznám, ale budiž, vím, o co jde. Každopádně to má Go implementačně dobře vyřešené.

Dobře vyřešené to je, ale má to svá plus a mínus. Hlavní výhodou tohoto řešení je, že samotný objekt je čistá struct, proto se s ním dá dobře manipulovat i přes FFI, a navíc volání metod může být u každého objektu buď statické, nebo dynamické (kachní) podle typu reference. Nevýhodou je, že reference můžou být různě velké, jak to ostatně tady překvapilo OP. Například v Rustu bude &Calculon normální pointer, ale &Worker dvojice pointerů a &[Calculon] bude pointer + usize. V C++ je to jednodušší, každá reference je jediný pointer, ale zase musí být vtable (neboli __methods) přímo součástí objektu, takže tento se tím stává složitý a obtížně přístupný "zvenčí".
Název: Re:Velikost pole objektů v Go
Přispěvatel: Šáša 10. 04. 2018, 00:37:29
Tak tuhle terminologii neznám, ale budiž, vím, o co jde. Každopádně to má Go implementačně dobře vyřešené.

Dobře vyřešené to je, ale má to svá plus a mínus. Hlavní výhodou tohoto řešení je, že samotný objekt je čistá struct, proto se s ním dá dobře manipulovat i přes FFI, a navíc volání metod může být u každého objektu buď statické, nebo dynamické (kachní) podle typu reference. Nevýhodou je, že reference můžou být různě velké, jak to ostatně tady překvapilo OP. Například v Rustu bude &Calculon normální pointer, ale &Worker dvojice pointerů a &[Calculon] bude pointer + usize. V C++ je to jednodušší, každá reference je jediný pointer, ale zase musí být vtable (neboli __methods) přímo součástí objektu, takže tento se tím stává složitý a obtížně přístupný "zvenčí".
Proč se k tomu vyjadřuješ, když v tom sám neskutečně plaveš?