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:
- Ar tipas žinomas iškvietimo vietoje? Uždarinys, konkretus tipas, generinis parametras — taip. Sąsaja — ne.
- Ar duomenys kerta
anyribą? Jei taip, viskas, kas didesnis už rodyklę, bus nukopijuota į krūvą.Itemyra 56 baitai; sąsajos reikšmė — 16. - 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.