計算機(jī)的歷史
算盤和機(jī)械計算機(jī)
有很多民族自豪感爆棚的兄弟會把算盤當(dāng)成計算機(jī)的起源,還有爆破天的兄弟會把陰陽當(dāng)成二進(jìn)制0和1的起源擒滑,我覺得這件事兒就有點兒不靠譜了
如果非要追究計算機(jī)的鼻祖挽唉,那就得講講17世紀(jì)前歐洲的故事牛哺,最早的計算機(jī)其實是計算器蟆豫,就是算數(shù)用的,在歐洲工業(yè)工業(yè)革命的時候,大量的工業(yè)模具需要計算世杀,歐洲又沒有中國傳統(tǒng)的計算器 - 算盤礁叔,就催生了很多科學(xué)家發(fā)明自己的計算器(對庐船,就是計算器,就是以前菜市場還在使用的那種,還不能稱之為現(xiàn)在的計算機(jī)),這其中有個NB的人物龄糊,這個人叫布萊士帕斯卡,我們的壓強(qiáng)單位(帕募疮,千帕炫惩,百帕,兆帕)等等阿浓,就是以這哥們兒的名字命名他嚷,還有,計算機(jī)語言里面有一種叫做Pascal,就是為了紀(jì)念他爸舒。
就是這么個NB的人物,發(fā)明了最早的機(jī)械計算器稿蹲,長這樣兒:
經(jīng)過后人的逐步改進(jìn)扭勉,機(jī)械計算機(jī)的最后發(fā)展堪稱精美,有長這樣兒的:
還有長成這樣兒的:
還有更NB的:
機(jī)械計算機(jī)改進(jìn)者中有個人值得一提苛聘,他就是德國百科全書式的天才涂炎,17世紀(jì)的亞里士多德 -- 萊布尼茨!
萊伯尼茲這個人又是個大牛设哗,他既懂物理又懂?dāng)?shù)學(xué)(物理數(shù)學(xué)不分家)唱捣,著名的微積分基本定理,牛頓萊布尼茨公式网梢,就是萊布尼茨發(fā)明的震缭,當(dāng)然這里面是牛頓跟萊布尼茨或者說英國跟歐洲大陸的恩怨情仇。簡單說战虏,萊布尼茨發(fā)表論文創(chuàng)立微積分公式拣宰,牛頓當(dāng)時是英國皇家學(xué)會的老大,話語權(quán)影響力比較大烦感。牛頓說萊布尼茨發(fā)表的公式是參考了牛頓三年前的筆記巡社,萊布尼茨嗓門不夠響,爭不過牛頓手趣,所以沒有辦法晌该,后人就把這個公式稱為牛頓萊布尼茨公式。
一個人想在社會取得回報或者想發(fā)揮巨大作用绿渣,就必須要明白這個社會的運(yùn)行機(jī)制朝群,通過這件事兒,大家應(yīng)該明白話語權(quán)的(傳媒怯晕、筆桿子)重要性潜圃,如果還不能理解,參考美國把上個世紀(jì)的美國病毒命名為西班牙病毒這件事兒舟茶,當(dāng)然最近又想把新冠病毒扣在我們腦袋上谭期,就是因為他把控了話語權(quán)。衍生出來你應(yīng)該明白的是吧凉,歷史是個任人打扮的小姑娘隧出,你看到的,你聽到的阀捅,都是別人想讓你看到和聽到的胀瞪,所以你要進(jìn)行深度的思考,他是誰?為什么這么說凄诞?他說的是真的嗎圆雁?對我有沒有什么企圖?多問自己幾個為什么帆谍,你會慢慢從白癡成為智者伪朽。
扯遠(yuǎn)了,還說回來萊布尼茨汛蝙,他除了改進(jìn)機(jī)械計算機(jī)以外烈涮,還有一個重要的發(fā)明,那就是大名鼎鼎的二進(jìn)制=呀!(這里終于跟現(xiàn)代IT技術(shù)關(guān)聯(lián)起來了)據(jù)說二進(jìn)制的發(fā)明是參考中國古代的陰陽太極圖而創(chuàng)作出來的坚洽,對此,我覺得倒是真的有可能西土。因為萊布尼茨有一本著名的著作讶舰,叫做《論中國人的自然哲學(xué)》,說明這個人對中國是有研究的翠储。而且绘雁,他發(fā)明了二進(jìn)制以后,還通知了當(dāng)時的康熙大帝援所,因為他認(rèn)為康熙大帝是個數(shù)學(xué)迷(對此我深表懷疑)庐舟。
當(dāng)然,機(jī)械計算機(jī)又大又笨重住拭,早就被現(xiàn)代的電子計算機(jī)所取代挪略,不過說句題外話,機(jī)械計算機(jī)也有電子計算機(jī)所不具備的優(yōu)點滔岳,就是結(jié)實耐用杠娱,幾百年都不壞,而且谱煤,還不用電 摊求,誰要是大學(xué)食堂里面打飯收費(fèi)做計算的時候來這么一臺,那絕對是學(xué)妹眼中最酷的仔刘离!
順便也來一張現(xiàn)代電子計算機(jī)的鼻祖(當(dāng)然室叉,第一臺電子計算機(jī)這件事兒也是見仁見智,美國嗓門大硫惕,所以現(xiàn)在資料大多認(rèn)為1946誕生于美國賓夕法尼亞大學(xué)的“ENIAC”是世界上第一臺電子計算機(jī))茧痕,它長這樣兒:
這是個龐然大物,它大概占地一個別墅恼除,跟一輛前蘇聯(lián)虎式坦克一樣重踪旷,每個小時耗電150度,但是,每秒鐘的計算量僅區(qū)區(qū)的5000次令野,要知道現(xiàn)在手機(jī)上的芯片的計算速度可以達(dá)到每秒10 0000 0000 0000次舀患。不過就是這樣一臺還比上菜市場計算器的東西,開啟了20世紀(jì)最NB的數(shù)字化革命气破!從此之后构舟,計算機(jī)行業(yè)飛速發(fā)展,造就了現(xiàn)在所謂的信息化大革命堵幽。
嚴(yán)格講,這臺機(jī)器應(yīng)該稱作電子管計算機(jī)弹澎,因為朴下,這里面用的零件全部都是電子管,電子管如果開關(guān)的速度太快苦蒿,很容易就會壞掉殴胧,據(jù)說這臺機(jī)器每天都會有電子管冒煙兒,工程師在尋找和修復(fù)每一個電子管中疲于奔命佩迟,想象一天24小時团滥,計算時間僅有半小時,剩下的23個半小時都是在尋找和修復(fù)壞掉的點报强,這是多么讓人抓狂的一件事灸姊。如果你不能理解這件事兒,想象一下一個燈泡每秒不停地開關(guān)5000次秉溉,它會不會壞掉力惯。而且,電子管還有很嚴(yán)重的發(fā)熱問題召嘶,需要把風(fēng)扇進(jìn)行緊密的排布父晶,這也是一個工藝難題。
不過弄跌,幸運(yùn)的是甲喝,在這臺又笨重毛病又多的計算機(jī)問世的第二年,也就是1947年铛只,美國貝爾實驗室研究發(fā)明了晶體管埠胖,和電子管相比,晶體管體積又小格仲,耗電還低押袍,最重要每秒開關(guān)幾十萬上億次都不帶壞的,從這一刻開始凯肋,計算機(jī)革命才真正的進(jìn)入了突飛猛進(jìn)的時代谊惭。
這堂課,我們要講的就是計算機(jī)的原理。
CPU的原理
為什么講線程要講CPU圈盔?因為線程和CPU有一對一的對應(yīng)關(guān)系1尽(超線程除外)
當(dāng)然,現(xiàn)代的計算機(jī)的核心驱敲,也就是芯片铁蹈,是由10 0000 0000 零件構(gòu)成,我沒有辦法帶你走遍這里面的每一個細(xì)節(jié)众眨,不過握牧,作為高級語言的程序員,我會帶你走到足夠深的深度娩梨,讓你能夠深入理解你寫的每一行代碼到底在計算機(jī)內(nèi)部是怎么轉(zhuǎn)換成電信號沿腰,從而被精密執(zhí)行的。這一點很重要狈定,因為這會給你帶來“通透感”(原諒我找不到更好的形容詞颂龙,現(xiàn)在很多程序員是沒有經(jīng)過科班訓(xùn)練的,是根據(jù)業(yè)務(wù)進(jìn)行速成的纽什,對這樣的小伙伴兒來說措嵌,你寫的代碼雖然可以工作,但是它對你是一個黑盒子芦缰,你看不到代碼背后的一切企巢,從而也就無法進(jìn)行更深入的理解和更準(zhǔn)確的調(diào)優(yōu),總之让蕾,我個人非常喜歡這種通透感包斑,我不喜歡一個技術(shù)對我來說是黑盒,是秘密涕俗,希望你也能理解和享受這種通透感)
好吧罗丰,讓我們揭開代碼背后的神秘世界吧。
還要從一個故事談起再姑。
我小時候最喜歡的女同學(xué)叫小芳萌抵,長得好看又善良,我們倆情投意合元镀,每天放學(xué)后都約會共同進(jìn)步绍填,童年的時候山青水白,鳥語花香栖疑,環(huán)境特別好讨永,我們的年紀(jì)都很小,我愛談天她愛笑遇革,有一回并肩坐在桃樹下卿闹,風(fēng)在林梢鳥在叫揭糕,不知怎么就睡著了,夢里花落知多少...
不要打斷我锻霎,讓我陷在美好的回憶中不可自拔一會兒著角。
只不過后來大人發(fā)現(xiàn)了我們的聯(lián)系,用他們自帶的污穢的思想旋恼,認(rèn)為我們的關(guān)系是污穢的吏口,是不純潔的,我們當(dāng)時還沒有羅密歐與朱麗葉冰更,梁山伯與祝英臺這樣的覺悟产徊,不懂得以死相爭,所以就被雙方家長棒打鴛鴦蜀细,各自關(guān)了禁閉囚痴。
不過這個難不倒剛剛學(xué)了電學(xué)的我,我們就設(shè)立了這樣入門級別的電路:
我還發(fā)明了燈泡語言:
亮亮 = 放
亮滅 = 學(xué)
滅亮 = 等
滅滅 = 我
當(dāng)然你會發(fā)現(xiàn)如果只有兩個信號的組合审葬,就最多表示四個字,如果想溝通更順暢奕谭,我只要增加信號的組合長度就可以了涣觉,比如三個信號,我就可以表示八個字
亮亮亮 = 放
亮亮滅 = 學(xué)
亮滅亮 = 等
亮滅滅 = 我
滅滅亮 = 一
滅滅滅 = 起
滅亮滅 = 電
滅亮亮 = 影
如果想交流的更加復(fù)雜血柳,我可以增加更長的信號組合官册,比如我如果用16個長度的信號,就可以表示2^16個漢字难捌,這個數(shù)字是65536膝宁,要知道,我們?nèi)粘5臐h字常用的話也就4000個左右根吁,整個康熙字典的總字?jǐn)?shù)也僅僅47000個员淫,我用燈泡信號的長度僅需要16個信號長,就足矣涵蓋中文的交流了击敌。
思考題:如果僅需要覆蓋日常交流(4000個漢字)介返,我需要的信號組合的長度至少是多少?
燈泡語言有些復(fù)雜沃斤,我結(jié)合萊布尼茨的二進(jìn)制圣蝎,用1來代表燈泡亮(通電),用0來代表燈泡滅(斷電)衡瓶,這樣我和小芳就有了自己的通信語言徘公,比如下面這句話,你猜我說了什么哮针?
111 110 001 000 = (? )把答案寫到括號里关面。
話說到這里坦袍,不知道大家有沒有發(fā)現(xiàn),我發(fā)明了一種漢字編碼缭裆,就是把特定的漢字用0和1的組合表示出來键闺,注意,漢字的編碼并不是只有一種方式澈驼,完全有可能發(fā)生的是辛燥,在一種的編碼方式中,111代表'我'缝其,而在另外一種編碼方式中111代表'中'挎塌,如果我們在解析一段編碼的用錯了編碼格式,就會出現(xiàn)平時經(jīng)常遇見的'亂碼'問題内边。
思考題:A編碼中榴都,111 = 我 110 = 你,B編碼中 111 = 沙 110 = 雕漠其,那么下面這段話究竟代表什么呢嘴高?
110 111 110
再有了第一個電路的基礎(chǔ)之上,我有設(shè)計了下面的電路:
這里就有了輸入和輸出的概念了
輸入1輸入2輸出
000
010
100
111
可以用這樣的符號表示:
也可以有這樣的電路:
加法器
輸入1輸入2加和輸出進(jìn)位輸出
0000
0110
1010
1101
時鐘
ram 保存信號
程序 - 自動化(時鐘信號 +
薦書
《編碼 隱匿在計算機(jī)軟硬件背后的語言》《Code: The Hidden Language of Computer Hardware and Software》
程序的執(zhí)行
進(jìn)程與線程
一個程序和屎,讀入內(nèi)存拴驮,全是0和1構(gòu)成
從內(nèi)存讀入到CPU計算,這個時候要通過總線
怎么區(qū)分一段01的數(shù)據(jù)到底是數(shù)據(jù)還是指令柴信?
總線分類為三種:控制線 地址線 數(shù)據(jù)線
一個程序的執(zhí)行套啤,首先把可執(zhí)行文件放到內(nèi)存,找到起始(main)的地址随常,逐步讀出指令和數(shù)據(jù)潜沦,進(jìn)行計算并寫回到內(nèi)存。
什么是進(jìn)程绪氛?什么是線程唆鸡?
一個程序進(jìn)入內(nèi)存,被稱之為進(jìn)程枣察?一個QQ.exe可以運(yùn)行多份兒嗎喇闸?
同一個進(jìn)程內(nèi)部:有多個任務(wù)并發(fā)執(zhí)行的需求(比如,一邊計算询件,一邊接收網(wǎng)絡(luò)數(shù)據(jù)燃乍,一邊刷新界面)
能不能用多進(jìn)程?可以宛琅,但是毛病多刻蟹,最嚴(yán)重的毛病是,我可以很輕易的搞死別的進(jìn)程
線程的概念橫空出世:共享空間嘿辟,不共享計算
進(jìn)程是靜態(tài)的概念:程序進(jìn)入內(nèi)存舆瘪,分配對應(yīng)資源:內(nèi)存空間片效,進(jìn)程進(jìn)入內(nèi)存,同時產(chǎn)生一個主線程
線程是動態(tài)的概念:是可執(zhí)行的計算單元(任務(wù))
一個ALU同一個時間只能執(zhí)行一個線程
同一段代碼為什么可以被多個線程執(zhí)行英古?
線程的切換
保存上下文淀衣,保存現(xiàn)場
問題:是不是線程數(shù)量越多,執(zhí)行效率越高召调?(初級)
展開:調(diào)度算法怎么選膨桥?(難)
問題:單核CPU多線程執(zhí)行有沒有意義?(初級)
問題:對于一個程序唠叛,設(shè)置多少個線程合適只嚣?(線程池設(shè)定多少核心線程?)(中高級)
線程調(diào)度器算法(平均時間片艺沼、CFS(考慮權(quán)重))
CPU的并發(fā)控制
關(guān)中斷
緩存一致性協(xié)議
CPU的速度和內(nèi)存的速度(100 :1)
這里的速度值得是ALU訪問寄存器的速度比訪問內(nèi)存的速度快100倍
為了充分利用CPU的計算能力册舞,在CPU和內(nèi)存中間引入緩存的概念(工業(yè)上的妥協(xié),考慮性價比)
現(xiàn)在的工業(yè)實踐障般,多采用三級緩存的架構(gòu)
緩存行:一次性讀取的數(shù)據(jù)塊
程序的局部性原理:空間局部性 時間局部性
如果緩存行大:命中率高调鲸,但讀取效率低。如果緩存行型斓础:命中率低藐石,但讀取效率高。
工業(yè)實踐的妥協(xié)結(jié)果徐伐,目前(2021)的計算機(jī)多采用64bytes (64 * 8bit)為一行
由于緩存行的存在,我們必須有一種機(jī)制募狂,來保證緩存數(shù)據(jù)的一致性办素,這種機(jī)制被稱為緩存一致性協(xié)議。
系統(tǒng)屏障
程序真的是按照“順序”執(zhí)行的嗎祸穷?
CPU的亂序執(zhí)行
Disorder這個程序性穿,證明亂序執(zhí)行的確存在
為什么會亂序?主要是為了提高效率(在等待費(fèi)時的指令執(zhí)行的時候雷滚,優(yōu)先執(zhí)行后面的指令)
線程的as-if-serial
單個線程需曾,兩條語句,未必是按順序執(zhí)行
單線程的重排序祈远,必須保證最終一致性
as-if-serial:看上去像是序列化(單線程)
會產(chǎn)生的后果
多線程會產(chǎn)生不希望看到的結(jié)果
ThisEscape(this 溢出問題)
推薦《Effective Java》- 不要在構(gòu)造方法中啟動線程呆万!
哪些指令可以互換順序
hanppens-before原則(JVM規(guī)定重排序必須遵守的規(guī)則)
JLS17.4.5 (不需要記住)
?程序次序規(guī)則:同一個線程內(nèi)车份,按照代碼出現(xiàn)的順序谋减,前面的代碼先行于后面的代碼,準(zhǔn)確的說是控制流順序扫沼,因為要考慮到分支和循環(huán)結(jié)構(gòu)出爹。
?管程鎖定規(guī)則:一個unlock操作先行發(fā)生于后面(時間上)對同一個鎖的lock操作庄吼。
?volatile變量規(guī)則:對一個volatile變量的寫操作先行發(fā)生于后面(時間上)對這個變量的讀操作。
?線程啟動規(guī)則:Thread的start( )方法先行發(fā)生于這個線程的每一個操作严就。
?線程終止規(guī)則:線程的所有操作都先行于此線程的終止檢測总寻。可以通過Thread.join( )方法結(jié)束梢为、Thread.isAlive( )的返回值等手段檢測線程的終止渐行。
?線程中斷規(guī)則:對線程interrupt( )方法的調(diào)用先行發(fā)生于被中斷線程的代碼檢測到中斷事件的發(fā)生,可以通過Thread.interrupt( )方法檢測線程是否中斷
?對象終結(jié)規(guī)則:一個對象的初始化完成先行于發(fā)生它的finalize()方法的開始抖誉。
?傳遞性:如果操作A先行于操作B殊轴,操作B先行于操作C,那么操作A先行于操作C