多線程下盆昙,C++如何調(diào)用Python腳本的方法

視頻教程:多線程場(chǎng)景下诊县,用C++調(diào)用Python腳本的方法

Git: https://github.com/JasonLiThirty/C-andPython

接口函數(shù)

Python3.6提供給C/C++接口函數(shù)缎浇,基本都是定義pylifecycle.h骡楼,pythonrun.h熔号,ceval.h中。

Py_Initialize() 和 Py_Finalize()

  • C++應(yīng)用程序調(diào)用Python腳本之前鸟整,必須先調(diào)用Py_Initialize()進(jìn)行初始化引镊,這個(gè)API用來(lái)分配Python解釋器使用的全局資源,應(yīng)用程序結(jié)束時(shí)需要調(diào)用Py_Finalize()來(lái)關(guān)閉Python的使用環(huán)境篮条。

Py_IsInitialized()

  • 用來(lái)判斷Python解釋器是否初始化成功弟头,true為成功,false為失敗涉茧。

PyErr_Print() & PyErr_Clear()

  • 執(zhí)行Python出錯(cuò)時(shí)赴恨,PyErr_Print()可將錯(cuò)誤信息顯示出來(lái),PyErr_Clear()將錯(cuò)誤信息在Python解釋器的緩存清除。

PyRun_SimpleString()

  • 這個(gè)函數(shù)能夠用來(lái)執(zhí)行簡(jiǎn)單的Python語(yǔ)句。

PyEval_InitThreads()

  • 如果使用多線程調(diào)用Python腳本失受,就需要在初始化Python解釋器時(shí)調(diào)用PyEval_InitThreads()來(lái)啟用線程支持(導(dǎo)致Python內(nèi)部啟用線程鎖)勺阐,最好在主線程啟動(dòng)時(shí)就調(diào)用。該API同時(shí)也鎖定全局解釋鎖匹舞,所以,還需要在初始化完成后需要自行釋放鎖。
  • 如果不需要使用多線程汛聚,不建議啟用該選項(xiàng),互斥鎖也會(huì)不可避免的增加系統(tǒng)開銷短荐。

PyEval_AcquireLock() & PyEval_ReleaseLock()

  • 因?yàn)镻ython編輯器不是線程安全的倚舀,為了支持多線程叹哭, Python 使用了互斥使訪問內(nèi)部數(shù)據(jù)結(jié)構(gòu)串行化。這種互斥即 “全局解釋器鎖 – global interpreter lock”痕貌,當(dāng)某個(gè)線程想使用 Python 的C API的時(shí)候风罩,它必須獲得全局解釋器鎖。所以多線程調(diào)用Python腳本前必須先持有這個(gè)全局解釋器鎖舵稠,然后才能進(jìn)行對(duì)Python的一系列操作超升。
  • 調(diào)用了 PyEval_AcquireLock之后,可以安全地假定你的線程已經(jīng)持有了鎖哺徊,其他相關(guān)線程不是被阻塞就是在執(zhí)行與 Python 解析器無(wú)關(guān)的代碼室琢。之后就可以開始執(zhí)行與Python相關(guān)的代碼了。
  • 調(diào)用了 PyEval_AcquireLock取得了鎖之后落追,必須確保運(yùn)行完需要的代碼后調(diào)用 PyEval_ReleaseLock 來(lái)釋放它盈滴,否則就會(huì)導(dǎo)致線程死鎖并凍結(jié)其他 Python 線程。

PyThreadState對(duì)象及其相關(guān)函數(shù)

每個(gè)Python 線程都需要維護(hù)自己的狀態(tài)信息轿钠,在被Python解釋器執(zhí)行時(shí)巢钓,需要先切換線程的狀態(tài)信息,才可以開始執(zhí)行相應(yīng)的代碼疗垛,這個(gè)線程狀態(tài)信息就是用PyThreadState這個(gè)對(duì)象來(lái)描述的症汹。

  • PyThreadState:每個(gè)Python 線程維護(hù)自己的狀態(tài)信息,存儲(chǔ)在 PyThreadState對(duì)象中贷腕。在多線程應(yīng)用中用 C 語(yǔ)言調(diào)用 Python API 函數(shù)時(shí)背镇,你必須維護(hù)自己的 PyThreadState 對(duì)象以便能安全地執(zhí)行并發(fā)的 Python 代碼。
  • PyInterpreterState:描述了幾個(gè)協(xié)作線程共享的狀態(tài)花履,屬于同一解釋器的線程共享它們的模塊維護(hù)和幾個(gè)其他的內(nèi)部子項(xiàng)芽世。
  • PyThreadState_Get():得到當(dāng)前PyThreadState的指針。一般用在初始化時(shí)用來(lái)得到主線程的PyThreadState對(duì)象诡壁。
  • PyThreadState_New():為新的C++線程創(chuàng)建一個(gè) PyThreadState 對(duì)象济瓢,需要用到既有的 PyInterpreterState 對(duì)象。該對(duì)象為所有參與的線程所共享的信息妹卿,初始化 Python 時(shí)旺矾,會(huì)自動(dòng)創(chuàng)建一個(gè) PyInterpreterState 對(duì)象,附加在主線程的 PyThreadState 對(duì)象上夺克, 所以可以利用PyInterpreterState 對(duì)象創(chuàng)建新的 PyThreadState箕宙。
  • PyThreadState_Swap():將要執(zhí)行Python代碼的線程特定的PyThreadState對(duì)象加載到解釋器
  • PyThreadState_Clear():重置線程狀態(tài)對(duì)象的所有相關(guān)信息。
  • PyThreadState_Delete():銷毀一個(gè)線程狀態(tài)對(duì)象铺纽,該對(duì)象的線程狀態(tài)必須提前調(diào)用 PyThreadState_Clear() 進(jìn)行清除柬帕。

以下是幾個(gè)進(jìn)階的接口函數(shù),這些函數(shù)可以將全局解釋器的加鎖和釋放鎖的操作,以及線程切換的操作封裝起來(lái)陷寝,比較方便锅很。

PyEval_AcquireThread(PyThreadState *tstate)

  • 獲得全局解釋器鎖并將當(dāng)前線程狀態(tài)設(shè)定為 tstate ,它不能為NULL凤跑。鎖必須提前創(chuàng)建爆安。如果線程已經(jīng)擁有鎖,會(huì)發(fā)生死鎖仔引。

PyEval_ReleaseThread(PyThreadState *tstate)

  • 重置當(dāng)前線程狀態(tài)為NULL并釋放全局解釋器鎖扔仓。鎖必須提前創(chuàng)建并且以在當(dāng)前線程中獲得。參數(shù) tstate 不能為 NULL咖耘。它只能用于校驗(yàn)它描述的當(dāng)前線程狀態(tài)——如果它不對(duì)翘簇,會(huì)報(bào)告一個(gè)致命錯(cuò)誤。這個(gè)函數(shù)在編譯時(shí)禁用線程支持的情況下不可用鲤看。

PyGILState_STATE state = PyGILState_Ensure()

  • 獲得全局解釋器鎖并自動(dòng)創(chuàng)建一個(gè)線程狀態(tài)缘揪,返回值是一個(gè)不透明的線程狀態(tài)“句柄”。

PyGILState_Release(PyGILState_STATE state)

  • 釋放全局解釋器鎖义桂,Python解析器線程狀態(tài)切換到調(diào)用PyGILState_Acquire之前的狀態(tài)。

PyGILState_Ensure() 和 PyGILState_Release()需要成對(duì)出現(xiàn)蹈垢,僅在CPython中有效慷吊,這樣就能實(shí)現(xiàn)Python解釋器的鎖功能。只有在關(guān)閉Python的使用環(huán)境時(shí)曹抬,可以不再需要調(diào)用PyGILState_Release()函數(shù)

示例代碼

Git: https://github.com/JasonLiThirty/C-andPython

PyInvoker

面向?qū)ο蟮姆椒▽?shí)現(xiàn)Python解釋器的管理和與Python腳本交互的實(shí)現(xiàn)溉瓶。

PyLock

運(yùn)用PyGILState_Acqsuire和PyGILState_ReleasePython的Global Interpreter Lock,來(lái)實(shí)現(xiàn)多線程之間數(shù)據(jù)完整性和狀態(tài)同步谤民,GIL機(jī)制能保證在任意時(shí)刻只有一個(gè)線程在解釋器中運(yùn)行堰酿,效率上會(huì)有一定的損失。

PythonGreet.py

def Hello(): print('Hello world!!!')

PythonCalc.py

def Add(num1, num2): return num1+num2

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末张足,一起剝皮案震驚了整個(gè)濱河市触创,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌为牍,老刑警劉巖哼绑,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異碉咆,居然都是意外死亡抖韩,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門疫铜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)茂浮,“玉大人,你說(shuō)我怎么就攤上這事∠浚” “怎么了顽馋?”我有些...
    開封第一講書人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)驹尼。 經(jīng)常有香客問我趣避,道長(zhǎng),這世上最難降的妖魔是什么新翎? 我笑而不...
    開封第一講書人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任程帕,我火速辦了婚禮,結(jié)果婚禮上地啰,老公的妹妹穿的比我還像新娘愁拭。我一直安慰自己,他們只是感情好亏吝,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開白布岭埠。 她就那樣靜靜地躺著,像睡著了一般蔚鸥。 火紅的嫁衣襯著肌膚如雪惜论。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,764評(píng)論 1 290
  • 那天止喷,我揣著相機(jī)與錄音馆类,去河邊找鬼。 笑死弹谁,一個(gè)胖子當(dāng)著我的面吹牛乾巧,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播预愤,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼沟于,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了植康?” 一聲冷哼從身側(cè)響起旷太,我...
    開封第一講書人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎向图,沒想到半個(gè)月后泳秀,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡榄攀,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年嗜傅,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片檩赢。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡吕嘀,死狀恐怖违寞,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情偶房,我是刑警寧澤趁曼,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站棕洋,受9級(jí)特大地震影響挡闰,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜掰盘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一摄悯、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧愧捕,春花似錦奢驯、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至邮偎,卻和暖如春管跺,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背禾进。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工伙菜, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人命迈。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像火的,于是被迫代替她去往敵國(guó)和親壶愤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348