A számítógép működése
A számítógépek és rajtuk futó szoftverek az univerzum legösszetettebb dolgai közé tartoznak. Talán egyedül csak a biológiai rendszerek komplexitása szárnyalja túl őket. Röviden vizsgáljuk meg, hogyan jutunk el erre a magas szintű összetettségre elemi részekből!
Alapvetően 4 logikailag elkülönülő elemből épül fel a számítógép hardvere:
- Processzor - Ez az eszköz, ami a számításokat végzi
- Memória - Tárolja a számításokhoz szükséges adatokat és a futtatható programot
- Bemeneti eszközök - Általuk vihetők be adatok és programok a számítógépbe
- Kimeneti eszközök - Általuk közli a számítógép a számítások eredményét
Emellett szükség van szoftverre más néven programra, ami meghajtja a processzort.
A számítógépen futtatható program igazából nem más, mint olyan utasítások egy sorozata, amit a processzor értelmezni képes.
Az utasítások sorozata modern (Neumann típusú) számítógépen a memóriában szerepel.
Ilyen utasítás lehet például, hogy a processzor adjon össze két a memóriában szereplő számot, vagy hogy adja meg, hogy két szám közül melyik a nagyobb. Ha egy parancsot végrehajtott a processzor, tovább ugrik a következőre és ez így megy addig, amíg véget nem ér a program.
Nehéz elképzelni, ám igaz, hogy az összes szoftver az operációs rendszerektől a hiperrealisztikus 3D játékokig ilyen és ehhez hasonló egyszerű matematikai és logikai műveletekre lebontható. A kulcs a számítógépek lélegzetelállító sebességében és a szoftverek egyre mélyebb bonyolultságában rejlik.
Az általunk megszokott, végtelenül összetett szoftverek ugyanúgy feldolgozhatók a számítógép számára, mint a legegyszerűbbek. Ezzel szemben az emberi programozók számára az utasítások végeláthatatlan sorozata nagyon hamar olvashatatlanná, felfoghatatlanná válik.
Ahhoz hogy ezt a komplexitást, kordában tudjuk tartani az informatika mérnökei újabb és újabb eszközöket készítettek arra, hogy a magas összetettségű problémákat, ember számára befogadható és fenntartható módon tudjuk kezelni.
Ezen eszközök közé tartoznak a programozási nyelvek is.
Programozási nyelvek
Ahogy a számítógép, úgy az agyunk is gigászi mennyiségű számítás végez minden pillanatban. Mégis a két “eszköz” működése nagyon különbözik. Csak képzeljük el, milyen nehezünkre esik, mennyi időt vesz igénybe két sokjegyű tizedes tört szám szorzása vagy osztása fejben, nem beszélve az elkövetett hibák számáról. Ezen műveletekből egy mai otthoni számítógép képességeit a másodpercenkénti ezer milliárdos nagyságrendben mérjük. Meglepő, hogy ezen látszólagos fényéves sebességelőny ellenére rengeteg feladatkörben a számítógépek mai napig reménytelenül kullognak emberszabású versenytásaik mögött különösképp a kreativitást és komplex tervezést igénylő területeken.
A különbség elsősorban architekturális. Az agyunk nagyon is máshogy épül fel és működik, mint egy processzor. Mi meg sem közelítjük, hogy olyan sebességgel gépiesen végezzünk hibátlanul matematikai és logikai műveleteket mint egy számítógép, ám az agyunk felépítése képessé tesz az absztrakt, strukturált gondolkodásra és problémamegoldásra.
Ember és gép kommunikációja
Talán megdöbbentőnek tűnhet valaki számára, aki nem ért a programozáshoz, de a programozók által szerkesztett kódok krikszkrakszai már ember számára nagyságrendekkel megérthetőbb, olvashatóbb és karbantarthatóbb verzió, mint a korai módjai a programozásnak, azaz a parancsok puszta felsorolása.
Ahogy megnéztük a számítógép csillagászati sebességgel hajtja végre az egyszerű matematikai műveletek végeláthatatlan sorozatát, de a processzor csak annyira okos, mint a rajta futó emberek által írt program. Ha csak egy apró karakter is téves a kódban, a számítógép a hibás programot fogja a rá jellemző hatékonysággal végrehajtani és az eredmény hibás vagy értelmezhetetlen lesz, esetleg hibaüzenettel le is áll a futás.
Az emberi nyelvek nagy helyet hagynak a saját értelmezésnek. Ha valaki felszólít arra, hogy “Cseréljem ki a a villanykörtét!”, a lehetőségek száma még ebben az egyszerű műveletben is óriási. Mire álljak rá, egy székre vagy keressek létrát? Ha székre, vegyem-e le a cipőmet? Hol találok villanykörtét, melyik fiókban, és mit tegyek ha épp nincs otthon? A sor folytatódhatna estig. Mindezen bizonytalanságok ellenére egy felnőtt, egészséges embernek minden bizonnyal nem fog nehezére esni mindezen problémák megoldása. Egy számítógép nem tud ehhez hasonlóan működni hiszen végletekig mechanikus működésű. Nem hajíthatunk neki utasításokat félvállról vagy csak hozzávetőlegesen körül írva. Az utasításoknak pontosaknak és formálisan definiáltaknak kell lenniük.
Tehát a fő különbségek ember és gép gondolkodása közt a következők:
- Az ember informálisan beszél és gondolkodik, a számítógép formálisan (100% pontossággal definiálandó a művelet)
- Az ember komplex és absztrakt fogalmak és kategóriák mentén dolgozik könnyedén, míg a számítógép matematikai műveletek sorozatával.
Azt, hogy egy programozási nyelv relatívan a társaihoz képest mely világhoz áll közelebb, a számítógépihez vagy az emberihez úgy szoktuk megfogalmazni, hogy a nyelv alacsony vagy magas szintű.
Például, míg a C egy a mai technológiai szinten jellemzően alacsony szintűnek tekintett nyelv, addig a C#, amit a Unity alatt is használunk, egyértelműen magas szintűnek sorolható.
Fontos kiemelni, hogy ez a kifejezés nem hordoz értékítéletet. Egy magasszintű nyelv nem jobb, mint egy alacsonyszintű. Mindkettőnek megvannak az előnyei a másikhoz képest és mindkettő lehet ideális választás feladattól függően, pont úgy ahogy a kalapács sem jobb se rosszabb a csavarhúzónál. Ezek különböző eszközök különböző feladatokra.
Specifikáció és algoritmus
Kicsit járjuk körbe, hogy mit jelent az, hogy valami ember számára olvasható!
Vegyünk egy példát: Tegyük fel, hogy építőkockák egy össze vissza sorát kell magasság szerint sorba rendeznünk. Ez egy olyan feladat, ami 4 éves kor felett nem szokott egészséges embernek problémát jelenteni.
A megoldáshoz nagyon sok részletet ki lehet dolgozni. Mikor melyik elemet mozgatom és hova? Viszont az, hogy szóban informatívan elmondtam, hogy mit is kell csinálni már elég információ volt ahhoz, hogy egy gyerek is nekiálljon a feladatnak. A feladatnak ezt az informális, részleteket nélkülöző és bizonytalanságokkal teli megfogalmazását nevezzük specifikációnak.
A specifikáció az első lépés egy szoftver vagy szoftvermodul életében egy megrendelő vagy bárki függetlenül attól hogy ért-e a programozáshoz megfogalmaz egy igényt. Minél kevesebb a bizonytalanság és félreérthetőség egy specifikációban annál jobb, de óhatatlanul nélkülözni fogja azt a szintjét a formalitásnak, amit a következő lépés jelent.
Mikor a számítógép számára elvégezhetővé akarunk tenni egy feladatot, az utolsó részletig ki kell azt dolgozni. Pontosan hogyan végezzük a sorba rakást? Tegyünk egy javaslatot!
Például megtehetjük azt, hogy megkeressük a legkisebbet az oszlopok közt, majd azt áttesszük egy újabb sorba, ezután a következő legkisebbet keressük meg és a legutóbbi átrakott után tesszük közvetlenül. Mindezt addig ismételjük, amíg el nem fogynak az oszlopaink az első sorból. Ezután a legkisebbtől indulva egyenként visszarakjuk a már sorbarendezett oszlopokat az eredeti helyükre.
Ez egy lehetséges stratégia, de korántsem az egyetlen. Mindez nem más, mint egy algoritmus, azaz egy pontos leírása egy feladat végrehajtásának vagy részletes útmutatás.
Aki már főzött pontosan recept alapján vagy követett Ikea összeszerelési kézikönyvet, az már találkozott és hajtott végre algoritmust.
Az algoritmus megfogalmazása még mindig emberi nyelven történik akár ábrákkal, diagrammokkal kiegészítve, de ez az utolsó lépés, ami elválaszt minket a programozástól. Ha tudjuk az algoritmust, és ismerünk egy magas szintű programozási nyelvet, egyikből úgy tudunk fordítani a másikra, mint egy tapasztalt szinkrontolmács spanyol és norvég közt. Ezen algoritmusok, informális leírások leképezésére lettek tervezve a programozási nyelvek.
Forrás, bytekód és fordítás
Egy programkód tehát emberi megértésre alkalmas, de ahogy előtte tárgyaltuk a számítógépnek is képesnek kell lennie értelmezni azt. Ám ha visszaemlékszünk azt állítottam, egy processzor csakis egy dolgot ért, egyszerű utasítások sorozatát, algoritmust nem. Ezért a programozó által készült kódot, az úgy nevezett forráskódot először le kell fordítani processzor által ismert műveletek egyszerű sorára melyet gépi kódnak vagy más néven bytekódnak nevezzük.
Ez a művelet a fordítás amelyet egy fordítóprogram végez.
A dolog persze nem ilyen egyszerű. A Unity alatt írt C# kódok nem gépi kódba fordulnak hanem egy úgynevezett köztes nyelvre vagy IL-re (Intermediate Language), amely nyelv futtatásáért egy újabb program, a CLR (Common Language Runtime) felel.
Ezt a megközelítést valós idejű JIT (Just In Time) fordításnak nevezik és előnye, hogy egy fordítással készült kódot futtathatunk több operációs rendszeren és processzor architektúrán is.