c include 多層目錄_python+C、C++混合編程的應用

e3fc41c929474d63f00ceb55a4b88868.png

TIOBE每個月都會新鮮出爐一份流行編程語言排行榜,這里會列出最流行的20種語言。

排序說明不了語言的好壞,反應的不過是某個軟件開發領域的熱門程度。語言的發展不是越來越common,而是越來越專注領域。有的語言專注于簡單高效,比如python,內建的list,dict結構比c/c++易用太多,但同樣為了安全、易用,語言也犧牲了部分性能。

在有些領域,比如通信,性能很關鍵,但并不意味這個領域的coder只能苦苦掙扎于c/c++的陷阱中,比如可以使用多種語言混合編程。

我看到的一個很好的Python與c/c++混合編程的應用是NS3(Network Simulator3)一款網絡模擬軟件,它的內部計算引擎需要用高性能,但在用戶建模部分需要靈活易用。NS3的選擇是使用C/C++來模擬核心部件和協議,用python來建模和擴展。

這篇文章介紹python和c/c++三種混合編程的方法,并對性能加以分析。

混合編程的原理

首先要說一下python只是一個語言規范,實際上python有很多實現:CPython是標準Python,是由C編寫的,python腳本被編譯成CPython字節碼,然后由虛擬機解釋執行,垃圾回收使用引用計數,我們談與C/C++混合編程實際指的是基于CPython解釋上的。

除此之外,還有Jython、IronPython、PyPy、Pyston,Jython是Java編寫的,使用JVM的垃圾回收,可以與Java混合編程,IronPython面向.NET平臺。

python與C/C++混合編程的本質是python調用C/C++編譯的動態鏈接庫,關鍵就是把python中的數據類型轉換成c/c++中的數據類型,給編譯函數處理,然后返回參數再轉換成python中的數據類型。

python中使用ctypes moduel,將python類型轉成c/c++類型

首先,編寫一段累加數值的c代碼:

extern "C"
{int addBuf(char* data, int num, char* outData);
}int addBuf(char* data, int num, char* outData){for (int i = 0; i < num; ++i)
{
outData[i] = data[i] + 3;
}return num;
}

然后,將上面的代碼編譯成so庫,使用下面的編譯指令

>gcc -pthread -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC addbuf.c -o addbuf.o

最后編寫python代碼,使用ctypes庫,將python類型轉換成c語言需要的類型,然后傳參調用so庫函數:

from ctypes import * # cdll, c_int
lib = cdll.LoadLibrary('libmathBuf.so')
callAddBuf = lib.addBuf
num = 4
numbytes = c_int(num)
data_in = (c_byte * num)()
for i in range(num):
data_in[i] = i
data_out = (c_byte * num)()
ret = lib.addBuf(data_in, numbytes, data_out) #調用so庫中的函數

在C/C++程序中使用Python.h,寫wrap包裝接口

這種方法需要修改c/c++代碼,在外部函數中處理入/出參,適配python的參數。寫一段c代碼將外部入參作為shell命令執行:


#include static PyObject* SpamError;static PyObject* spam_system(PyObject* self, PyObject* args){const char* command;int sts;if (!PyArg_ParseTuple(args, "s", &command)) //將args參數按照string類型處理,給command賦值return NULL;
sts = system(command); //調用系統命令if (sts < 0) {
PyErr_SetString(SpamError, "System command failed");return NULL;
}return PyLong_FromLong(sts); //將返回結果轉換為PyObject類型
}//方法表static PyMethodDef SpamMethods[] = {
{"system", spam_system, METH_VARARGS,"Execute a shell command."},
{NULL, NULL, 0, NULL}
};//模塊初始化函數PyMODINIT_FUNC initspam(void){
PyObject* m;//m = PyModule_Create(&spammodule); // v3.4
m = Py_InitModule("spam", SpamMethods);if (m == NULL)return;
SpamError = PyErr_NewException("spam.error",NULL,NULL);
Py_INCREF(SpamError);
PyModule_AddObject(m,"error",SpamError);
}

處理上所有的入參、出參都作為PyObject對象來處理,然后使用轉換函數把python的數據類型轉換成c/c++中的類型,返回參數按相同方式處理。比第一種方法多了初始化函數,這部分是把編譯的so庫當做python module所必需要做的。

python這樣使用:

imoprt spam
spam.system("ls")

使用c/c++編寫python擴展可以參見:http://docs.python.org/2.7/extending/extending.html

使用SWIG,來生成獨立的wrap文件

這種方式并不能算是一種新方式,實際上是基于第二中方式的一種包裝。SWIG是個幫助使用C或者C++編寫的軟件能與其它各種高級編程語言進行嵌入聯接的開發工具。SWIG能應用于各種不同類型的語言包括常用腳本編譯語言例如Perl, PHP, Python, Tcl, Ruby, PHP,C#,Java,R等。

操作上,是針對c/c++程序編寫獨立的接口聲明文件(通常很簡單),swig會分析c/c++源程序自動分析接口要如何包裝。在指定目標語言后,swig會生成額外的包裝源碼文件。編譯so庫時,把包裝文件一起編譯、連接即可。看個c代碼例子:

int system(const char* command){
sts = system(command);if (sts < 0) {return NULL;
}return sts;
}

c源碼中去掉適配python的包裝,僅定義system函數本身,這比第二種方式簡潔很多,并且剔除了c代碼與python的耦合代碼,是c代碼通用性更好。

然后編寫swig接口聲明文件spam.i:

%module spam%{#include "spam.h"%}%include "spam.h"%include "typemaps.i"
int system(const char* INPUT);

這是一段語言無關的模塊聲明,要創建一個叫spam的模塊,對system做一個聲明,主要是聲明參數作為入參使用。然后執行swig編譯程序:

>swig -c++ -python spam.i

swig會生成spam_wrap.cxx和spam.py兩個文件。先看spam_wrap.cxx,這個生成的文件很長,但關鍵的就是對函數的包裝:

ba144f50a1307a6cc690f5279094a87c.png

包裝函數傳入的還是PyObejct對象,內部進行了類型轉換,最終調了源碼中的system函數。

生成的了另一個spam.py實際上是對so庫又用python包裝了一層(實際比較多余):

e1d1192085dbae7183af30b41008cdba.png

這里使用_spam模塊,這里實際上是把擴展命名為了_spam。關于swig在python上的應用可以參見:http://www.swig.org/Doc1.3/Python.html

下面就是編譯和安裝python 模塊,Python提供了distutils module,可以很方便的編譯安裝python的module。像下面這樣寫一個安裝腳本setup.py:

8230ec3381a143c3cfd90807a6411433.png

執行 python setup.py build,即可以完成編譯,程序會創建一個build目錄,下面有編譯好的so庫。so庫放在當前目錄下,其實Python就可以通過import來加載模塊了。

當然也可以用 python setup.py install 把模塊安裝到語言的擴展庫——site-packages目錄中。關于build python擴展,可以參考https://docs.python.org/2/extending/building.html#building

混合編程性能分析

混合編程的使用場景中,很重要一個就是性能攸關。那么這小節將通過幾個小實驗驗證下混合編程的性能如何,或者說怎樣寫程序能發揮好混合編程的性能優勢。

我們使用冒泡排序算法來驗證性能。

1、實驗一 使用冒泡程序驗證python和c/c++程序的性能差距

python版冒泡程序:

def bubble(arr,length):
j = length - 1while j >= 0:
i = 0while i < j:if arr[i] > arr[i+1]:
tmp = arr[i+1]
arr[i+1] = arr[i]
arr[i] = tmp
i += 1
j -= 1

c語言版冒泡排序

void bubble(int* arr,int length){int j = length - 1;int i;int tmp;while(j >= 0){
i = 0;while(i < j){if(arr[i] > arr[i+1]){
tmp = arr[i+1];
arr[i+1] = arr[i];
arr[i] = tmp;
}
i += 1;
}
j -= 1;
}
}

?使用一個長度為100內容固定的數組,反復排序10000次(每次排序后,再把數組恢復成原始序列),記錄執行時間:在相同的機器上多次執行,Python版執行時間是10.3s左右,而c語言版本(未使用任何優化編譯參數)執行時間只有0.29s左右。相比之下python的性能的確差很多(主要是python中list的操作跟c的數組相比,效率差非常多),但python中很多擴展都是c語言寫的,目的就是為了提升效率,python用于數據分析的numpy庫就擁有不錯的性能。下個實驗就驗證,如果python使用c語言版本的冒泡排序擴展庫,性能會提升多少。2、實驗二 python語言使用ctypes方式調用

這里直接使用c_int來定義了數組對象,這也節省了調用時數據類型轉換的開銷:

import timefrom ctypes import *
IntArray100 = c_int * 100
arr = IntArray100(87,23,41, 3, 2, 9,10,23,0,21,5,15,93, 6,19,24,18,56,11,80,34, 5,98,33,11,25,99,44,33,78,52,31,77, 5,22,47,87,67,46,83, 89,72,34,69, 4,67,97,83,23,47, 69, 8, 9,90,20,58,20,13,61,99,7,22,55,11,30,56,87,29,92,67,99,16,14,51,66,88,24,31,23,42,76,37,82,10, 8, 9, 2,17,84,32,66,77,32,17, 5,68,86,22, 1, 0)... ...if __name__ == "__main__":
libbubble = CDLL('libbubble.so')
time1 = time.time()for i in xrange(100000):
libbubble.initArr(arr1,arr,100)
libbubble.bubble(arr1,100)
time2 = time.time()print time2 - time1

再次執行:

為了減少誤差,把循環增加到10萬次,結果c原生程序使用優化參數編譯后用時0.65s左右。python使用c擴展后(相同編譯參數)執行僅需2.3s左右。

3、實驗三 在c語言中使用PyObject處理入參

這種方式是在python中依然使用list裝入待排序數列,在c函數中把list賦值給數組,再進行排序,排好序后,再對原始list賦值。循環排序10萬次,執行用時1.0s左右。

4、實驗四 使用swig來包裝c方法

在接口文件中聲明%array_class(int,intArray);然后在Python中使用initArray來作為數組,同樣修改成10萬次排序。python版本的程序(相同編譯參數)執行僅需0.7s左右,比c原生程序慢大概7%。

結論

1.python 的list效率非常低,在高性能場景下避免對list大量循環、取值、賦值操作。如需要最好使用ctype中的數組,或者是用c語言來實現。

2.應該把耗時的cpu密集型的邏輯交給c/c++實現,python使用擴展即可。

- END -

原文鏈接:

https://blog.51cto.com/12557234/2294219

文源網絡,僅供學習之用,如有侵權,聯系刪除。

往期精彩

92c627e3e4943187070812e958902a03.png

◆ ?50款開源工具你都用過嗎?

◆ ?你知道Python的就業方向和薪資嗎?(贈學習資料)

◆ ?python網絡爬蟲的基本原理詳解

e6ee98a570047f2674bbb219372ecc26.png

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/530050.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/530050.shtml
英文地址,請注明出處:http://en.pswp.cn/news/530050.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

校友會2019中國大學計算機,校友會2019中國計算機類一流專業排名,清華大學排名第一...

原標題&#xff1a;校友會2019中國計算機類一流專業排名&#xff0c;清華大學排名第一中國哪些高校的計算機類本科專業躋身2019世界一流專業、中國頂尖專業和中國一流專業行列&#xff1f;哪些計算機類本科專業是2019年中國高考最優秀考生的最佳選擇&#xff1f;為了給2019年全…

查詢結果取交集_Elasticsearch 查詢過程中的 prefilter 原理

大家都知道在對索引執行查詢的時候&#xff0c;需要在所有的分片上執行查詢&#xff0c;因為無法知道被查詢的關鍵詞位于哪個分片&#xff0c;對于全文查詢來說誠然如此&#xff0c;然而對于時序型的索引&#xff0c;當你從 my_index-* 中執行 now-3d 的范圍查詢時&#xff0c;…

計算機專業人畢業設計外文翻譯,計算機專業畢業設計外文翻譯.doc

《計算機專業畢業設計外文翻譯.doc》由會員分享&#xff0c;提供在線免費全文閱讀可下載&#xff0c;此文檔格式為doc&#xff0c;更多相關《計算機專業畢業設計外文翻譯.doc》文檔請在天天文庫搜索。1、&#xfeff;近幾年來&#xff0c;隨著計算機的普及和建筑電子產業的發展…

語音識別插件_AnsweringMachine XS: 越獄理由之二,iPhone 電話語音答錄機

Apps & Tweaks| Jailbreak Guide| iDevicesTweak&#xff1a;AnsweringMachine XSVersion&#xff1a;XSRepo&#xff1a;http://limneos.net/iOS Support&#xff1a;12-13Price&#xff1a;3.99iOS 開發人員 Elias Limneos 開發了電話輔助系列插件&#xff0c;AnsweringM…

怎么在計算機里找到CF里保存的視頻,電腦怎么查看穿越火線錄制保存視頻?操作方法...

在Win10電腦上玩穿越火線&#xff0c;遇到精彩時刻我們都會錄制下&#xff0c;好跟朋友分享&#xff0c;但是在Win10電腦上穿越火線錄制保存之后的視頻&#xff0c;在哪看呢?有很多用戶都不知道怎么在Win10電腦查看這個穿越火線錄制保存的視頻&#xff0c;這個的話&#xff0c…

ironpython this_IronPython sys._getframe not found

問題Im currently building a program in C# which will call functions in provided python script files.Some of these script files calls _getframe() in sys, which results in the error:System.MissingMemberException: module object has no attribute_getframe(Since…

計算機賬務處理流程圖,賬務處理流程圖

手工業務流程圖賬務處理流程主要有 5 種形式&#xff1a;記賬憑證核算形式、科目匯總表核算形式、匯總記賬憑證核算形式、日記總賬核算形式、和多欄式日記賬核算形式。不同的賬務處理流程其差別主要體現在登記總賬的方法和依據不同&#xff0c;其中科目匯總表核算形式最為常見&…

css滑動門的用處,CSS滑動門是什么?有什么用處?[web前端培訓]

在制作網頁導航時&#xff0c;經常會碰到導航欄長度不同&#xff0c;但背景相同的情形。此時如果通過拉伸背景圖的方式來適應文本內容&#xff0c;就會造成背景圖變形。在制作網頁時&#xff0c;為了使各種特殊形狀的背景能夠自適應元素中的文本內容&#xff0c;并且不會變形&a…

vue 父鏈和子組件索引_vuejs填坑-父子組件之間的訪問

有時候我們需要父組件訪問子組件&#xff0c;子組件訪問父組件&#xff0c;或者是子組件訪問根組件。1. 父組件訪問子組件 $children或$ref$children 返回所有子組件的實例&#xff0c;是一個數組顯示兩個組件的信息{{ msg }}{{ msg }}Vue.component(child1, {template: #child…

python多線程爬取多個網頁_python多線程爬取網頁

#-*- encoding:utf8 -*-‘‘‘Created on 2018年12月25日author: Administrator‘‘‘from multiprocessing.dummy import Pool as plimport csvimport requestsfrom lxml import etreedef spider(url):header {"User-Agent":"Mozilla/5.0 (Windows NT 6.1; WO…

layui 分頁ajax,實現Ajax異步的layui分頁

頁面代碼:人才推薦姓名學歷技能經驗住址聯系方式 ${res}${data}于千萬年之中時間的無涯的荒野里…時間的無涯的荒野里…--%>js代碼//加載完成$(function(){var sherchkey${positioninfo.name};savePosition();//保存修改方法getPeopleList(1,5,sherchkey);//獲取人才列表// …

Gen系列服務器,新計算、新體驗 | 新華三全新HPE Gen10系列服務器響徹“云”端

數字經濟時代的數據中心正在加速向云計算融合&#xff0c;用戶將面臨傳統架構與云架構并存的混合IT模式。如何既擁有專有數據中心對數據完全可控以及對關鍵業務充分優化的優勢&#xff0c;又能擁有云計算的靈活彈性&#xff1f;如何有效利舊并滿足混合IT架構的需求&#xff1f;…

python 異常處理 變量_Python基礎入門:從變量到異常處理

一 . 條件語句1.if-else 語句當if語句后的條件結果表達式為假&#xff0c;則執行else 語句后的代碼。如若輸入數字非666&#xff0c;則會輸出“猜錯了&#xff0c;小姐姐現在心里想的為666“2.if 語句支持嵌套hi6 hi>2 執行 if hi>7 6<7 所以無輸出hi1 hi<2 執行 p…

web系統四層結構中服務器端,基于.NET平臺構建四層B/S結構的動態網站

摘要&#xff1a;Web是基于Internet技術的一種應用層服務,具有后臺數據庫支持的n層B&#xff0f;S結構已經成為動態Web應用的主流。雖然動態網站開發工作的主要是進行服務器端應用程序的開發,但是B&#xff0f;S結構動態Web的應用要涉及瀏覽器、Web服務器、服務器端應用程序、數…

收藏功能_微軟Edge獲得了新的收藏夾菜單、PDF功能等

作為其今年早些時候概述的戰略的一部分&#xff0c;微軟Edge現在正在向所有Windows 10 PC推出。與經典的Edge不同&#xff0c;Chromium Edge與任何特定的Windows更新無關&#xff0c;但微軟又開始為該瀏覽器進行了一系列令人興奮的改進。新的Edge基于Chromium&#xff0c;它還帶…

服務器LIMIT是什么信號,Postfix添加milter-limit配置方案

[安裝環境]操作系統&#xff1a;CentOS 5.6MAT&#xff1a;POSTFIX2.8.4安裝之前必須保證POSTFIX能正常收發信如果已經安裝過Berkeley Db3以上版本可以不安裝新的DB(但是注意引入db.so)[安裝步驟]1、milter-limit-0.14.tar.gz及libsnert-1.71.6.tar.gz包的獲取方法需要創建一個…

數據存儲方式_視頻監控系統的數據存儲方式的概念及應用

DAS&#xff1a;直連存儲&#xff0c;直連式存儲與服務器主機之間的連接通常采用SCSI連接&#xff0c;SCSI通道是IO瓶頸;服務器主機SCSI ID資源有限&#xff0c;能夠建立的SCSI通道連接有限。無論直連式存儲還是服務器主機的擴展&#xff0c;從一臺服務器擴展為多臺服務器組成的…

ubuntu18 防火墻關閉_Ubuntu 18.04 關閉及開啟防火墻

Ubuntu 內建使用 UFW (Uncomplicated Firewall) 作為防火墻管理工具, 一般情況下都會開啟防火墻, 但有些特殊情況, 例如測試環境需要關閉防火墻作測試, 或者對網絡設定進行除錯等。以下是在 Ubuntu 18.04 關閉防火墻的方法。首先檢查目前防火墻是否已經開啟, 執行以下指令:$ su…

vue從url中獲取token并加入到 請求頭里_輕流amp;amp;企業微信——獲取打卡數據...

企業微信開放了打卡應用的api&#xff0c;功能包括查詢打卡數據&#xff0c;能獲取到用戶、地點、時間、打卡類型等信息&#xff0c;在輕流中可以基于以上數據做一段時間內的遲到/事假等統計&#xff0c;以及更深層數據處理&#xff0c;方便管理。第一步&#xff1a;獲取access…

單片機串口通信學號顯示_觸摸屏與單片機串口通信測試

工業現場在使用觸摸屏的時候&#xff0c;與第三方控制器進行通信連接的時候&#xff0c;一般都是使用成熟的通信協議進行通信連接。而這些協議的實現過程&#xff0c;觸摸屏廠商也已經在編程環境中進行了封裝集成&#xff0c;對于使用的工程師來說&#xff0c;通信的數據交換過…