Tema
/
Algoritmai ir duomenų struktūros GO
Pamoka 13 / 15 Krūvos ir prioritetinės eilės ~55 min
Teorija

Taisyklė, suderinanti visus tris

Trys matavimai, trys skirtingi atsakymai, viena taisyklė.

pamoka standartinė biblioteka rezultatas
3 container/list lygiosios — 50 šuolių prieš 50
6 sort.Search laimėjo — 15 ns prieš 18
13 container/heap pralaimėjo — 1.66 karto

Pagunda būtų padaryti išvadą apie standartinę biblioteką. Bet trys skirtingi atsakymai reiškia, kad klausimas ne apie ją.

Taisyklė

Abstrakcija nemokama, kai kompiliatorius gali ją permatyti. Ji brangi, kai priverčia PAKUOTI DUOMENIS operacijai, kuri per maža, kad tą kainą paslėptų.

(Ketvirta pratybų užduotis atskiria pakavimą nuo iškvietimų per lentelę ir parodo, kad čia lemia pakavimas. Iškvietimas irgi kainuoja, bet šiuo atveju — nepamatuojamai mažai.)

Dvi sąlygos, ir antroji svarbi ne mažiau už pirmąją. Iškvietimas per lentelę kainuoja maždaug tiek pat, ką jis apgaubia, ar tai būtų vienas palyginimas, ar visas failo nuskaitymas. Skiriasi ne kaina, o santykis.

Kaip trys atvejai į ją telpa

6 pamoka — kompiliatorius mato viską. sort.Search gauna uždarinį, sukurtą toje pačioje vietoje. Konkretus tipas žinomas, tad Go jį įterpia; po optimizacijos lieka tas pats ciklas, kurį parašei ranka. Nulis pakavimo, nulis iškvietimų. Abstrakcija dingsta.

13 pamoka — kompiliatorius nemato nieko. container/heap reikalauja sąsajos. Elementai eina per any (pakavimas, 20 000 paskirstymų), o Less ir Swap kviečiami per lentelę. Ir apgaubiama operacija yra vienas palyginimas — mažiausia įmanoma. Santykis blogiausias, koks gali būti.

3 pamoka — nėra ko permatyti. container/list metodai apibrėžti konkretiems tipams (*List, *Element), ne sąsajai. Jokios lentelės, jokio dinaminio kreipimosi. Vienintelis any ten yra saugoma Value, pakuojama kartą įterpiant — o trečia pamoka matavo ėjimą, ne įterpimą. Todėl ir lygiosios: kelyje nieko nebuvo.

Kas iš to seka praktikoje

Ne „naudok standartinę biblioteką" ir ne „rašyk ranka karštą kodą". Nė vienas iš šitų neatlaiko trijų matavimų iš eilės.

Užduok tris klausimus:

  1. Ar tipas žinomas iškvietimo vietoje? Uždarinys, konkretus tipas, generinis parametras — taip. Sąsaja — ne.
  2. Ar duomenys kerta any ribą? Jei taip, viskas, kas didesnis už rodyklę, bus nukopijuota į krūvą. Item yra 56 baitai; sąsajos reikšmė — 16.
  3. Kokio dydžio operacija apgaubiama? Vienas palyginimas — kaina matoma. Failo nuskaitymas — kainos nė nepastebėsi.

Trys „taip, ne, maža" reiškia sort.Search. „Ne, taip, maža" reiškia container/heap. Būtent taip ir išėjo.

Ir kada tai iš viso svarbu

Šeštoje pamokoje sort.Search buvo greitesnė ir trumpesnė ir jau ištestuota. Ten rinktis lengva.

Čia ranka rašyta krūva laimi 1.66 karto — bet tai 0.8 ms 10 000 elementų. Šeštoje pamokoje jau matei, kaip tokio dydžio skirtumai atrodo šalia tikro darbo: transit medžio ginčas visas telpa į dešimtąją milisekundės dalį ir dėl to nieko nesprendžia.

1.66 karto svarbu tada, kai operacija atliekama milijonus kartų. Tavo algo top — ne. Dijkstros algoritmas grafe su 10 000 mazgų — taip, ir aštuntas žingsnis parodo, kiek tai kainuoja realiai.

Todėl atsakymas nėra „rašyk krūvą ranka". Atsakymas yra: žinok, kodėl viena abstrakcija nemokama, o kita ne, ir mokėk pamatuoti, kuriuo atveju esi.