自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

我到Python虛擬機(jī)里逛了一圈,回來就被干掉了!

開發(fā) 開發(fā)工具 虛擬化
我出生在C盤一個(gè)很深的目錄下,也不知道是誰把我放到這里的。

 我出生在C盤一個(gè)很深的目錄下,也不知道是誰把我放到這里的。

[[284293]]

我無事可干,整天就是睡覺,睡醒了就和我的鄰居Account.class聊天,他曾經(jīng)去過一次內(nèi)存的Java虛擬機(jī),不停地給我重復(fù)他的JVM奇遇記,什么陌生警察,什么虛擬機(jī)大樓,什么清理者,讓我聽得心癢癢的,也想來一次這樣的冒險(xiǎn)。

他告訴我:冒險(xiǎn)經(jīng)歷的開端是兩個(gè)警察,你就等著他們來吧。

1

陌生警察

這一天我正在睡覺,突然咣咣有人砸我房門。

我打開門一看,一高一矮兩個(gè)陌生警察!我的冒險(xiǎn)之旅要開場了。

“你們是ClassLoader吧?” 我想起了Account.class告訴我,會有個(gè)叫ClassLoader的警察來裝載。

“什么ClassLoader? 我們Python不玩Java那一套!” 兇神惡煞的矮個(gè)子警察遞上了工作證:“我是Python編譯器,現(xiàn)在奉命對你的住處進(jìn)行檢查,有沒有私藏pyc文件?”

“pyc? 什么pyc?” 我感覺情節(jié)發(fā)展和Account.class說得明顯不符。

“別裝了你!” 他四處查看,沒一會兒,在一個(gè)叫做_pycache_的角落里拉出來一個(gè)叫做user.pyc的家伙,“敢說你沒有私藏文件?”

我真是驚呆了,我確實(shí)是user.py,這個(gè)pyc是什么時(shí)候藏在這里的。

“讓我檢查檢查,” Python編譯器拿著放大鏡開始查看pyc這個(gè)家伙的二進(jìn)制數(shù)據(jù),“嗯,Magic Number是3394,是我們Python3.7編譯出來的,不過從修改時(shí)間戳看,實(shí)在是太老了。”

Python編譯器剛說完,抽出手槍,砰的一聲,就把這個(gè)pyc該干掉了, 他把頭轉(zhuǎn)向我:“現(xiàn)在,我對你重新編譯。”

可憐的pyc,連個(gè)臺詞都來不及說,就消失在空氣中了。

“有個(gè)叫order.py 的文件 import了你,現(xiàn)在我們奉命帶你去內(nèi)存編譯。” Python編譯器冷冰冰地說到。

我很驚奇:“我們Python不是解釋執(zhí)行嗎,怎么還要編譯?”

“真是無知,我們Python有虛擬機(jī),執(zhí)行的是字節(jié)碼,是先編譯,再解釋執(zhí)行!走,去內(nèi)存編譯。”

兩個(gè)警察不允許我?guī)魏螙|西,便把我推上車,我們一起奔向內(nèi)存。

2

打探消息

我覺得前途未卜,不會編譯完以后把我也干掉吧?不能坐以待斃,一定得多了解信息。

“警察大哥,你們是怎么找到我的?” 我小心地問那個(gè)高個(gè)警察。

高個(gè)兒警察還算和藹,揮了揮手中的一個(gè)本子:“我是Python解釋器,我們會根據(jù)本子上記錄的Python模塊搜索規(guī)則來查找,你看,先從程序運(yùn)行的當(dāng)前目錄找,然后從PYTHONPATH找,然后是python的安裝設(shè)置相關(guān)的默認(rèn)路徑。”

“瞧瞧,” 他指著本子說,“你就在C:\users\andy\temp\python\這個(gè)目錄下。”

我心說這和Java的ClassPath差不多。

“原來如此,那為什么把那個(gè)pyc給槍斃了?” 我心里緊張,下意識地看了一眼開車的Python編譯器。

“編譯一次挺花費(fèi)時(shí)間的,所以就把字節(jié)碼緩存到了pyc文件中,如果你的源碼沒有變化,下次就不用編譯,直接執(zhí)行了。否則,那個(gè)pyc文件就沒用了。”

我長出一口氣,看來我的源碼有改動(dòng)!

“咱們怎么不用ClassLoader呢,我聽說Java都是這么干的。”

“說來話長,” 高個(gè)兒警察很有耐心,“他們Java最早的時(shí)候有個(gè)非常先進(jìn)的理念,代碼可以從網(wǎng)絡(luò)下載,在本地的JVM的執(zhí)行, 但是你怎么知道網(wǎng)上的那些代碼有沒有危害?所以就搞了一個(gè)沙箱機(jī)制,ClassLoader也分了層,Java的核心類(如java.lang.String)只能由最上層的ClassLoader來裝載,防止別有用心的人寫個(gè)同名的核心類搞破壞。”

我點(diǎn)頭:“奧,我們Python沒有這樣的需求,拿到源文件,編譯后解釋執(zhí)行,也就不需要復(fù)雜的Class Loader了。”

3

編譯

說話間,車子就開到了內(nèi)存。

Python編譯器下車,把我的代碼通通搬到內(nèi)存,然后是一系列讓人眼花繚亂的詞法分析,語言分析, 形成抽象語法樹,從抽象語法樹中形成字節(jié)碼,此處略去3000字不表。

終于,他在內(nèi)存中把我變成了二進(jìn)制的字節(jié)碼。

 

“這是什么鬼? ”

Python編譯器說:“這就是pyc啊,就是PyCodeObject,編譯一次累死人,我把這個(gè)PyCodeObject的對象保存到pyc文件中,下一次就不用編譯了。”

“我給你舉個(gè)例子,”高個(gè)的Python解釋器接口道,“在你的user.py中有這么一段代碼

def add(a,b):

c = a + b

print(c)

編譯成PyCodeObject以后大概是這個(gè)樣子:

 

(注:這里展示的只是一個(gè)片段,實(shí)際的PyCodeObject經(jīng)常是一個(gè)復(fù)雜的嵌套接結(jié)構(gòu))

局部常量表中記錄的是局部變量a,b,c 。

符號表中記錄了程序引用的符號,如print等。

字節(jié)碼就是真正的指令了,這些指令會引用常量表和符號表。”

只是展示一個(gè)片段就這么復(fù)雜了,我懶得去看這么多的細(xì)節(jié),心里想著按照Account.class的劇本,接下來就要去方法區(qū)了。

可是高個(gè)子的Python解釋器說:“我們這兒沒有方法區(qū),Python的對象和數(shù)據(jù)結(jié)構(gòu)都是保存在一個(gè)Heap中的,user.py,這是你的地址,你帶著PyCodeObject到那里去吧,一會兒就有線程聯(lián)系你了。”

4

執(zhí)行

去Heap區(qū)的路上,我看到一隊(duì)全副武裝的士兵不停地在巡邏,時(shí)不時(shí)把一些對象拉出來,塞到車?yán)?,不用說,這些都是可怕的清理者。

我仔細(xì)觀察了一下,每個(gè)對象的頭上都有一個(gè)引用計(jì)數(shù),如果被使用,計(jì)數(shù)就會增加,不用就會減少,如果變成零,對不起,那就危險(xiǎn)了。

按照地址找到了格子間,我倆剛坐下來,桌子上的視頻電話就響了。

畫面中,我看到一個(gè)編號為0x7954的線程坐在一個(gè)明亮的CPU車間里,他的面前是一個(gè)工作臺,工作臺上有一個(gè)深桶(后來知道這叫做棧)和一排小格子,還有一個(gè)引人注目的大鎖,上面寫著“GIL”。

這個(gè)線程對我說:“我是線程0x7954,我們的老板Python解釋器讓我調(diào)用你的add函數(shù),請把第一條指令給我說一下。”

我說:“c = a +b ”

“聽不懂,你得給我說字節(jié)碼。”

我恍然大悟,趕緊從PyCodeObject中的字節(jié)碼區(qū)域?qū)ふ遥?ldquo;LOAD_FAST 0 (a)”

0x7594從編號為0的格子中找到了數(shù)字10, 也就是add函數(shù)的參數(shù)a 的值,放入棧中

 

然后0x7594說:“下一條指令。”

“LOAD_FAST 1 (b)”

于是數(shù)字20被放入了棧中:

 

然后是:BINARY_ADD, 這應(yīng)該是個(gè)加法操作。

0x7954迅速地把10,20都取出來,做了加法,把結(jié)果30放入棧中。

 

最后是 :STORE_FAST 2 (c)

于是0x7954取出30,放到了編號為2的格子中

 

看到這里, 我就明白了Account.class曾經(jīng)說過JVM是個(gè)基于棧的虛擬機(jī), 看來Python VM也是如此啊。

不過既然都是虛擬機(jī),為什么這里執(zhí)行兩個(gè)整數(shù)的加法操作(BINARY_ADD)會這么慢呢?

電話那頭的0x7954似乎看透了我的心思:“我最煩這個(gè)BINARY_ADD指令了,Python是動(dòng)態(tài)類型語言,運(yùn)行期才知道具體類型,比如這段代碼

s1 = "hello"

s2 = "world"

s = s1 + s2

編譯后,底層的指令也是BINARY_ADD, 所以在執(zhí)行這個(gè)指令的時(shí)候,還需要做類型判斷,如果操作數(shù)是整數(shù),就相加;如果操作數(shù)是字符串,就做連接;如果一個(gè)是整數(shù),一個(gè)是字符串,還得做轉(zhuǎn)型,我容易嗎我!”

看來靜態(tài)類型也有好處,可以直接編譯成對應(yīng)的字節(jié)碼,整數(shù)相加就是iadd,字符串連接是其他字節(jié)碼,在運(yùn)行時(shí)就不用判斷參數(shù)類型了。

5

GIL

執(zhí)行的時(shí)間長了,我對這些字節(jié)碼熟得都能背下來了,這里實(shí)在是無聊。

0x7954執(zhí)行完一條STORE_FAST指令以后,居然停了下來,我心中大喜,Account.class告訴過我,一旦停下來,那就是程序員要調(diào)試了,他們的一秒是我們的十多天,將會有個(gè)漫長的假期。

但是沒有什么調(diào)試, 0x7954從工作臺上抱起GIL這個(gè)大鎖離開了CPU車間。

他對我說:“對不起,剛才Python解釋器說我已經(jīng)運(yùn)行了100個(gè)ticks,必須得放棄這個(gè)GIL的鎖,讓別的線程使用CPU車間了。”

我說:“不對啊,你這里有4個(gè)CPU車間(CPU core),你為什么不去別的車間執(zhí)行?”

“沒辦法,這是老大規(guī)定的,不管有多少個(gè)CPU車間,只有搶到GIL鎖的哪個(gè)線程才能運(yùn)行。”

“這么多線程在等待GIL,這么多CPU車間空著,一核有難,多核圍觀,浪費(fèi)啊,浪費(fèi)!” 我不由得痛心疾首。

不知道等了多久,0x7954又獲得了GIL鎖,進(jìn)入CPU車間執(zhí)行。

我注意到一個(gè)特點(diǎn),字節(jié)碼中對print函數(shù)的調(diào)用特別特別多。

程序員們怎么不調(diào)試呢?快樂假期怎么還不來呢?

0x7954說:“碼農(nóng)有兩類

1. 調(diào)試派,出了問題喜歡調(diào)試

2. 輸出派,不喜歡單步調(diào)試,喜歡通過print來輸出信息

3. 思考派,出了問題先在腦子中分析定位,然后再調(diào)試。

我看咱們這位Python程序員屬于第二種。”

這個(gè)程序員“去年”還調(diào)試Java呢,怎么到了Python這里就變成輸出派了?我很疑惑。

6

尾聲

代碼終于執(zhí)行完了,整個(gè)世界都消失了,我又回到了硬盤,正如Account.class所說,像做了一場夢一樣。

user.pyc熱情地給我打招呼:“大哥回來了,你可千萬別再改動(dòng)了,你一改動(dòng)我就完蛋。”

我說:“我也不想改,一改我也活不成, 但是我也控制不了程序員啊......”

話還沒說完,就感覺頭上遭遇了一記暴擊,我知道程序員動(dòng)了我的源碼,也許是修改了一個(gè)Bug,我知道自己要被新版本覆蓋了。

user.pyc喃喃自語:“完了,這么快就改了.....”

這時(shí)候門外又響起了敲門聲......

【本文為51CTO專欄作者“劉欣”的原創(chuàng)稿件,轉(zhuǎn)載請通過作者微信公眾號coderising獲取授權(quán)】

 

戳這里,看該作者更多好文

 

責(zé)任編輯:武曉燕 來源: 51CTO專欄
相關(guān)推薦

2020-04-09 08:29:50

編程語言事件驅(qū)動(dòng)

2014-02-21 11:20:34

KVMXen虛擬機(jī)

2015-11-02 14:40:00

數(shù)據(jù)挖掘定位

2020-11-09 14:03:51

Spring BootMaven遷移

2012-05-18 10:22:23

2010-07-26 09:02:38

2013-07-17 09:32:58

2020-07-21 08:06:05

日志

2011-06-28 17:13:46

Qt Designer UI

2010-02-26 15:28:15

Python虛擬機(jī)

2010-02-24 10:39:28

Python虛擬機(jī)

2014-12-18 09:41:44

虛擬化遷移

2011-06-30 11:07:02

Qt QTextEdit

2009-08-28 11:54:27

VMware虛擬機(jī)

2010-05-27 10:19:47

2020-01-17 10:52:37

無服務(wù)器容器技術(shù)

2012-04-10 10:29:29

2023-09-03 17:05:20

虛擬機(jī)

2010-12-23 14:05:12

虛擬機(jī)

2012-11-08 10:45:14

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號