一文學(xué)會(huì) Python 多線程編程

Threading 模塊從Python 1.5.2版開(kāi)始出現(xiàn),用于增強(qiáng)底層的多線程模塊 thread 。Threading 模塊讓操作多線程變得更簡(jiǎn)單穴豫,并且支持程序同時(shí)運(yùn)行多個(gè)操作渤滞。

注意,Python 中的多線程最好用于處理有關(guān) I/O 的操作因俐,如從網(wǎng)上下載資源或者從本地讀取文件或者目錄拇惋。如果你要做的是 CPU 密集型操作,那么你需要使用 Python 的 multiprocessing 模塊抹剩。這樣做的原因是撑帖,Python 有一個(gè)全局解釋器鎖 (GIL),使得所有子線程都必須運(yùn)行在同一個(gè)主線程中澳眷。正因?yàn)槿绱撕伲?dāng)你通過(guò)多線程來(lái)處理多個(gè) CPU 密集型任務(wù)時(shí),你會(huì)發(fā)現(xiàn)它實(shí)際上運(yùn)行的更慢钳踊。因此衷敌,我們將重點(diǎn)放在那些多線程最擅長(zhǎng)的領(lǐng)域:I/O 操作!

線程簡(jiǎn)介

多線程能讓你像運(yùn)行一個(gè)獨(dú)立的程序一樣運(yùn)行一段長(zhǎng)代碼拓瞪。這有點(diǎn)像調(diào)用子進(jìn)程(subprocess)缴罗,不過(guò)區(qū)別是你調(diào)用的是一個(gè)函數(shù)或者一個(gè)類(lèi),而不是獨(dú)立的程序吴藻。在我看來(lái)瞒爬,舉例說(shuō)明更有助于解釋。下面來(lái)看一個(gè)簡(jiǎn)單的例子:

這里沟堡,我們導(dǎo)入 threading 模塊并且創(chuàng)建一個(gè)叫 doubler 的常規(guī)函數(shù)侧但。這個(gè)函數(shù)接受一個(gè)值,然后把這個(gè)值翻一番航罗。它還會(huì)打印出調(diào)用這個(gè)函數(shù)的線程的名稱(chēng)禀横,并在最后打印一行空行。然后在代碼的最后一塊粥血,我們創(chuàng)建五個(gè)線程并且依次啟動(dòng)它們柏锄。在我們實(shí)例化一個(gè)線程時(shí),你會(huì)注意到复亏,我們把 doubler 函數(shù)傳給 target 參數(shù)趾娃,同時(shí)也給 doubler 函數(shù)傳遞了參數(shù)。Args 參數(shù)看起來(lái)有些奇怪缔御,那是因?yàn)槲覀冃枰獋鬟f一個(gè)序列給 doubler 函數(shù)抬闷,但它只接受一個(gè)變量,所以我們把逗號(hào)放在尾部來(lái)創(chuàng)建只有一個(gè)參數(shù)的序列。

需要注意的是笤成,如果你想等待一個(gè)線程結(jié)束评架,那么需要調(diào)用 join() 方法。

當(dāng)你運(yùn)行以上這段代碼炕泳,會(huì)得到以下輸出內(nèi)容:

當(dāng)然纵诞,通常情況下你不會(huì)希望輸出打印到標(biāo)準(zhǔn)輸出。如果不幸真的這么做了培遵,那么最終的顯示效果將會(huì)非痴丬剑混亂。你應(yīng)該使用 Python 的 logging 模塊荤懂。它是線程安全的茁裙,并且表現(xiàn)出色塘砸。讓我們用logging 模塊修改上面的例子并且給我們的線程命名节仿。代碼如下:

代碼中最大的改變就是加入了 get_logger 函數(shù)。這段代碼將創(chuàng)建一個(gè)被設(shè)置為調(diào)試級(jí)別的日志記錄器掉蔬。它將日志保存在當(dāng)前目錄(即腳本運(yùn)行所在的目錄)下廊宪,然后設(shè)置每行日志的格式。格式包括時(shí)間戳女轿、線程名箭启、日志記錄級(jí)別以及日志信息。

在 doubler 函數(shù)中蛉迹,我們把 print 語(yǔ)句換成 logging 語(yǔ)句傅寡。你會(huì)注發(fā)現(xiàn),在創(chuàng)建線程時(shí)北救,我們給 doubler 函數(shù)傳入了 logger 對(duì)象荐操。這樣做的原因是,如果在每個(gè)線程中實(shí)例化 logging 對(duì)象珍策,那么將會(huì)產(chǎn)生多個(gè) logging 單例(singleton)托启,并且日志中將會(huì)有很多重復(fù)的內(nèi)容。

最后攘宙,創(chuàng)建一個(gè)名稱(chēng)列表屯耸,然后使用 name 關(guān)鍵字參數(shù)為每一個(gè)線程設(shè)置具體名稱(chēng),這樣就可以為線程命名蹭劈。運(yùn)行以上代碼疗绣,將會(huì)得到包含以下內(nèi)容的日志文件:

輸出結(jié)果不言自明,所以繼續(xù)介紹其他內(nèi)容铺韧。在本節(jié)中再多說(shuō)一點(diǎn)多矮,即通過(guò)繼承threading.Thread 實(shí)現(xiàn)多線程。舉最后一個(gè)例子祟蚀,通過(guò)繼承 threading.Thread 創(chuàng)建子類(lèi)工窍,而不是直接調(diào)用 Thread 函數(shù)割卖。

更新后的代碼如下:


這個(gè)例子中,我們只是創(chuàng)建一個(gè)繼承于 threading.Thread 的子類(lèi)患雏。像之前一樣鹏溯,傳入一個(gè)需要翻一番的數(shù)字,以及 logging 對(duì)象淹仑。但是這次丙挽,設(shè)置線程名稱(chēng)的方式有點(diǎn)不太一樣,變成了通過(guò)調(diào)用 thread 對(duì)象的 setName 方法來(lái)設(shè)置匀借。不過(guò)仍然需要調(diào)用 start 來(lái)啟動(dòng)線程颜阐,不過(guò)你可能注意到我們并不需要在子類(lèi)中定義該方法。當(dāng)調(diào)用 start 時(shí)吓肋,它會(huì)通過(guò)調(diào)用 run 方法來(lái)啟動(dòng)線程凳怨。在我們的類(lèi)中,我們調(diào)用 doubler 函數(shù)來(lái)做處理是鬼。輸出結(jié)果中除了一些添加的額外信息內(nèi)容幾乎差不多肤舞。運(yùn)行下這個(gè)腳本,看看你會(huì)得到什么均蜜。

線程鎖與線程同步

當(dāng)你有多個(gè)線程李剖,就需要考慮怎樣避免線程沖突。我的意思是說(shuō)囤耳,你可能遇到多個(gè)線程同時(shí)訪問(wèn)同一資源的情況篙顺。如果不考慮這些問(wèn)題并且制定相應(yīng)的解決方案,那么在開(kāi)發(fā)產(chǎn)品過(guò)程中充择,你總會(huì)在最糟糕的時(shí)候遇到這些棘手的問(wèn)題德玫。

解決辦法就是使用線程鎖。鎖由 Python 的 threading 模塊提供聪铺,并且它最多被一個(gè)線程所持有化焕。當(dāng)一個(gè)線程試圖獲取一個(gè)已經(jīng)鎖在資源上的鎖時(shí),該線程通常會(huì)暫停運(yùn)行铃剔,直到這個(gè)鎖被釋放撒桨。來(lái)讓我們看一個(gè)非常典型沒(méi)有卻應(yīng)具備鎖功能的例子:

如果往以上代碼添加time.sleep函數(shù)并給出不同長(zhǎng)度的時(shí)間,可能會(huì)讓這個(gè)例子更有意思键兜。無(wú)論如何凤类,這里的問(wèn)題是,一個(gè)線程可能已經(jīng)調(diào)用update_total函數(shù)并且還沒(méi)有更新完成普气,此時(shí)另一個(gè)線程也有可能調(diào)用它并且嘗試更新內(nèi)容谜疤。根據(jù)操作執(zhí)行順序的不同,該值可能只被增加一次。

讓我們給這個(gè)函數(shù)添加鎖夷磕。有兩種方法可以實(shí)現(xiàn)履肃。第一種方式是使用try/finally,從而確保鎖肯定會(huì)被釋放坐桩。下面是示例:

如上尺棋,在我們做任何處理之前就獲取鎖。然后嘗試更新 total 的值绵跷,最后釋放鎖并打印出 total 的當(dāng)前值膘螟。事實(shí)上,我們可以使用 Python 的 with 語(yǔ)句避免使用try/finally這種較為繁瑣的語(yǔ)句:

正如你看到的那樣碾局,我們不再需要try/finally作為上下文管理器荆残,而是由 with 語(yǔ)句作為替代。

當(dāng)然你也會(huì)遇到要在代碼中通過(guò)多個(gè)線程訪問(wèn)多個(gè)函數(shù)的情況净当。當(dāng)你第一次編寫(xiě)并發(fā)代碼時(shí)内斯,代碼可能是這樣的:

這樣的代碼在上面的情況下能夠正常工作,但假設(shè)你有多個(gè)線程都調(diào)用這兩個(gè)函數(shù)呢蚯瞧。當(dāng)一個(gè)線程正在運(yùn)行這兩個(gè)函數(shù)嘿期,然后另外一個(gè)線程也可能會(huì)修改這些數(shù)據(jù),最后得到的就是不正確的結(jié)果埋合。問(wèn)題是,你甚至可能沒(méi)有馬上意識(shí)到結(jié)果錯(cuò)了萄传。有什么解決辦法呢甚颂?讓我們?cè)囍页龃鸢浮?/p>

通常首先想到的就是在調(diào)用這兩個(gè)函數(shù)的地方上鎖。讓我們?cè)囍薷纳厦娴睦有懔猓薷某扇缦滤荆?/p>

當(dāng)你真正運(yùn)行這段代碼時(shí)振诬,你會(huì)發(fā)現(xiàn)它只是掛起了。究其原因衍菱,是因?yàn)槲覀冎桓嬖Vthreading模塊獲取鎖赶么。所以當(dāng)我們調(diào)用第一個(gè)函數(shù)時(shí),它發(fā)現(xiàn)鎖已經(jīng)被獲取脊串,隨后便把自己掛起了辫呻,直到鎖被釋放,然而這將永遠(yuǎn)不會(huì)發(fā)生琼锋。

真正的解決辦法是使用重入鎖(Re-Entrant Lock)放闺。threading 模塊提供的解決辦法是使用RLock 函數(shù)。即把lock = threading.lock()替換為lock = threading.RLock()缕坎,然后重新運(yùn)行代碼怖侦,現(xiàn)在代碼就可以正常運(yùn)行了。

如果你想在線程中運(yùn)行以上代碼,那么你可以用以下代碼取代直接調(diào)用 main 函數(shù):

每個(gè)線程都會(huì)運(yùn)行 main 函數(shù)匾寝,main 函數(shù)則會(huì)依次調(diào)用另外兩個(gè)函數(shù)搬葬。最終也會(huì)產(chǎn)生 10 組結(jié)果集。

定時(shí)器

Threading 模塊有一個(gè)優(yōu)雅的 Timer 類(lèi)艳悔,你可以用它來(lái)實(shí)現(xiàn)在指定時(shí)間后要發(fā)生的動(dòng)作踩萎。它們實(shí)際上會(huì)啟動(dòng)自己的自定義線程,通過(guò)調(diào)用常規(guī)線程上的 start() 方法即可運(yùn)行很钓。你也可以調(diào)用它的cancel 方法停止定時(shí)器香府。值得注意的是,你甚至可以在開(kāi)始定時(shí)器之前取消它码倦。

有一天企孩,我遇到一個(gè)特殊的情況:我需要與已經(jīng)啟動(dòng)的子進(jìn)程通信,但是我需要它有超時(shí)處理袁稽。雖然處理這種特殊問(wèn)題有很多不同的方法勿璃,不過(guò)我最喜歡的解決方案是使用 threading 模塊的 Timer 類(lèi)。

在下面這個(gè)例子中推汽,我們將使用 ping 指令作為演示补疑。在 Linux 系統(tǒng)中,ping 命令會(huì)一直運(yùn)行下去直到你手動(dòng)殺死它歹撒。所以在 Linux 世界里莲组,Timer 類(lèi)就顯得非常方便。示例如下:

這里我們?cè)?lambda 表達(dá)式中調(diào)用 kill 殺死進(jìn)程暖夭。接下來(lái)啟動(dòng) ping 命令锹杈,然后創(chuàng)建 Timer 對(duì)象。你會(huì)注意到迈着,第一個(gè)參數(shù)就是需要等待的秒數(shù)竭望,第二個(gè)參數(shù)是需要調(diào)用的函數(shù),緊跟其后的參數(shù)是要調(diào)用函數(shù)的入?yún)⒃2ぁT诒纠幸澹覀兊暮瘮?shù)是一個(gè) lambda 表達(dá)式,傳入的是一個(gè)只有一個(gè)元素的列表奴潘。如果你運(yùn)行這段代碼旧烧,它應(yīng)該會(huì)運(yùn)行 5 秒鐘,然后打印出 ping 的結(jié)果萤彩。

其他線程組件

Threading 模塊包含對(duì)其他功能的支持粪滤。例如,你可以創(chuàng)建信號(hào)量(Semaphore)雀扶,這是計(jì)算機(jī)科學(xué)中最古老的同步原語(yǔ)之一杖小∷列冢基本上,一個(gè)信號(hào)量管理一個(gè)內(nèi)置的計(jì)數(shù)器予权。當(dāng)你調(diào)用 acquire 時(shí)計(jì)數(shù)器就會(huì)遞減昂勉,相反當(dāng)你調(diào)用 release 時(shí)就會(huì)遞增。根據(jù)其設(shè)計(jì)扫腺,計(jì)數(shù)器的值無(wú)法小于零岗照,所以如果正好在計(jì)數(shù)器為零時(shí)調(diào)用 acquire 方法,該方法將阻塞線程笆环。

譯者注:通常使用信號(hào)量時(shí)都會(huì)初始化一個(gè)大于零的值攒至,如semaphore = threading.Semaphore(2)

另一個(gè)非常有用的同步工具就是事件(Event)。它允許你使用信號(hào)(signal)實(shí)現(xiàn)線程通信躁劣。在下一節(jié)中我們將舉一個(gè)使用事件的實(shí)例迫吐。

最后,在Python 3.2中加入了 Barrier 對(duì)象账忘。Barrier 是管理線程池中的同步原語(yǔ)志膀,在線程池中多條線程需要相互等待對(duì)方。如果要傳遞 barrier鳖擒,每一條線程都要調(diào)用 wait() 方法溉浙,在其他線程調(diào)用該方法之前線程將會(huì)阻塞。全部調(diào)用之后將會(huì)同時(shí)釋放所有線程蒋荚。

線程通信

某些情況下戳稽,你會(huì)希望線程之間互相通信。就像先前提到的圆裕,你可以通過(guò)創(chuàng)建 Event 對(duì)象達(dá)到這個(gè)目的广鳍。但更常用的方法是使用隊(duì)列(Queue)。在我們的例子中吓妆,這兩種方式都會(huì)有所涉及。下面讓我們看看到底是什么樣子的:


讓我們掰開(kāi)揉碎分析一下吨铸。首先行拢,我們有一個(gè)創(chuàng)建者(creator)函數(shù)(亦稱(chēng)作生產(chǎn)者(producer)),我們用它來(lái)創(chuàng)建想要操作(或者消費(fèi))的數(shù)據(jù)诞吱。然后用另外一個(gè)函數(shù)my_consumer 來(lái)處理剛才創(chuàng)建出來(lái)的數(shù)據(jù)舟奠。Creator 函數(shù)使用 Queue 的 put 方法向隊(duì)列中插入數(shù)據(jù),消費(fèi)者將會(huì)持續(xù)不斷的檢測(cè)有沒(méi)有更多的數(shù)據(jù)房维,當(dāng)發(fā)現(xiàn)有數(shù)據(jù)時(shí)就會(huì)處理數(shù)據(jù)沼瘫。Queue 對(duì)象處理所有的獲取鎖和釋放鎖的過(guò)程,這些不用我們太關(guān)心咙俩。

在這個(gè)例子中耿戚,先創(chuàng)建一個(gè)列表湿故,然后創(chuàng)建兩個(gè)線程,一個(gè)用作生產(chǎn)者膜蛔,一個(gè)作為消費(fèi)者坛猪。你會(huì)發(fā)現(xiàn),我們給兩個(gè)線程都傳遞了 Queue 對(duì)象良漱,這兩個(gè)線程隱藏了關(guān)于鎖處理的細(xì)節(jié)丙唧。隊(duì)列實(shí)現(xiàn)了數(shù)據(jù)從第一個(gè)線程到第二個(gè)線程的傳遞坑傅。當(dāng)?shù)谝粋€(gè)線程把數(shù)據(jù)放入隊(duì)列時(shí),同時(shí)也傳遞一個(gè) Event 事件就斤,緊接著掛起自己,等待該事件結(jié)束蘑辑。在消費(fèi)者側(cè)洋机,也就是第二個(gè)線程,則做數(shù)據(jù)處理工作以躯。當(dāng)完成數(shù)據(jù)處理后就會(huì)調(diào)用 Event 事件的 set 方法槐秧,通知第一個(gè)線程已經(jīng)把數(shù)據(jù)處理完畢了,可以繼續(xù)生產(chǎn)了忧设。

最后一行代碼調(diào)用了 Queue 對(duì)象的 join 方法刁标,它會(huì)告知 Queue 等待所有線程結(jié)束。當(dāng)?shù)谝粋€(gè)線程把所有數(shù)據(jù)都放到隊(duì)列中址晕,它也就運(yùn)行結(jié)束了膀懈。


結(jié)束語(yǔ)

以上涵蓋了關(guān)于線程的諸多方面,主要包括:


線程基礎(chǔ)知識(shí)

鎖的工作方式

什么是事件以及如何使用

如何使用定時(shí)器

通過(guò) Queues/Events 實(shí)現(xiàn)線程間通信

現(xiàn)在你們知道如何使用線程以及線程擅長(zhǎng)什么了谨垃,希望在你們的代碼中能有它們的用武之地启搂。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市刘陶,隨后出現(xiàn)的幾起案子胳赌,更是在濱河造成了極大的恐慌,老刑警劉巖匙隔,帶你破解...
    沈念sama閱讀 216,470評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件疑苫,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡纷责,警方通過(guò)查閱死者的電腦和手機(jī)捍掺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)再膳,“玉大人挺勿,你說(shuō)我怎么就攤上這事∥蛊猓” “怎么了不瓶?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,577評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵禾嫉,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我湃番,道長(zhǎng)夭织,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,176評(píng)論 1 292
  • 正文 為了忘掉前任吠撮,我火速辦了婚禮尊惰,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘泥兰。我一直安慰自己弄屡,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布鞋诗。 她就那樣靜靜地躺著膀捷,像睡著了一般。 火紅的嫁衣襯著肌膚如雪削彬。 梳的紋絲不亂的頭發(fā)上全庸,一...
    開(kāi)封第一講書(shū)人閱讀 51,155評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音融痛,去河邊找鬼壶笼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛雁刷,可吹牛的內(nèi)容都是我干的覆劈。 我是一名探鬼主播,決...
    沈念sama閱讀 40,041評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼沛励,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼责语!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起目派,我...
    開(kāi)封第一講書(shū)人閱讀 38,903評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤坤候,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后企蹭,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體铐拐,經(jīng)...
    沈念sama閱讀 45,319評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評(píng)論 2 332
  • 正文 我和宋清朗相戀三年练对,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吹害。...
    茶點(diǎn)故事閱讀 39,703評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡螟凭,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出它呀,到底是詐尸還是另有隱情螺男,我是刑警寧澤棒厘,帶...
    沈念sama閱讀 35,417評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站下隧,受9級(jí)特大地震影響奢人,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜淆院,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評(píng)論 3 325
  • 文/蒙蒙 一何乎、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧土辩,春花似錦支救、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,664評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至启涯,卻和暖如春贬堵,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背结洼。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,818評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工黎做, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人补君。 一個(gè)月前我還...
    沈念sama閱讀 47,711評(píng)論 2 368
  • 正文 我出身青樓引几,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親挽铁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子伟桅,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • 來(lái)源:數(shù)據(jù)分析網(wǎng)Threading 模塊從 Python 1.5.2 版開(kāi)始出現(xiàn),用于增強(qiáng)底層的多線程模塊 thr...
    PyChina閱讀 1,738評(píng)論 0 5
  • 線程 操作系統(tǒng)線程理論 線程概念的引入背景 進(jìn)程 之前我們已經(jīng)了解了操作系統(tǒng)中進(jìn)程的概念,程序并不能單獨(dú)運(yùn)行更扁,只有...
    go以恒閱讀 1,641評(píng)論 0 6
  • 一文讀懂Python多線程 1盖腕、線程和進(jìn)程 計(jì)算機(jī)的核心是CPU,它承擔(dān)了所有的計(jì)算任務(wù)浓镜。它就像一座工廠溃列,時(shí)刻在運(yùn)...
    星丶雲(yún)閱讀 1,453評(píng)論 0 4
  • 一. 操作系統(tǒng)概念 操作系統(tǒng)位于底層硬件與應(yīng)用軟件之間的一層.工作方式: 向下管理硬件,向上提供接口.操作系統(tǒng)進(jìn)行...
    月亮是我踢彎得閱讀 5,965評(píng)論 3 28
  • 私以為生活中總是會(huì)萌生出許多儀式感……比如讀書(shū),古人會(huì)選擇焚香沐浴膛薛,以敬畏和純凈侍書(shū)……現(xiàn)在的我們更多的可能是...
    怪誕城之夜閱讀 322評(píng)論 0 0