使用pybind11用C++為python寫pyd,讓C++代碼執(zhí)行速度再提升50倍的終極大殺器,讓python的數(shù)值計(jì)算的速度徹底起飛~~,讓量化投資的行業(yè)中性速度跨進(jìn)1秒大關(guān)~

前一篇文章python之使用pybind11調(diào)用C為數(shù)值計(jì)算加速,python和C++混編極限提速之終極方法,讓你的python數(shù)值計(jì)算速度起飛主要介紹了使用C給python寫模塊的一些基本知識,本篇主要借助一個(gè)例子,來看下用C來計(jì)算到底可以有多快。

在多因子處理的過程中,對于因子的行業(yè)中性計(jì)算是運(yùn)算量比較大,在因子處理時(shí)會(huì)花費(fèi)比較多時(shí)間的一個(gè)環(huán)節(jié)。本篇就用Z-score方法來對因子進(jìn)行行業(yè)中性化計(jì)算為例子,來看看到底行業(yè)中性計(jì)算可以達(dá)到什么樣的速度。

話不多說,先把C的計(jì)算代碼框架拿出來,然后分析下行業(yè)中性化的運(yùn)算結(jié)構(gòu)。

1.? ? 輸入?yún)?shù)為兩個(gè),一個(gè)是原始因子矩陣,另一個(gè)是和因子矩陣相對應(yīng)的行業(yè)代碼矩陣。

2.? ? ?返回結(jié)果為和原因子矩陣大小一致的行業(yè)中性化后的矩陣。

3.? ? ?最外層循環(huán)是對行的循環(huán),也就是對時(shí)間循環(huán)。

4.? ? ?內(nèi)層首先對列循環(huán)分別計(jì)算相同行業(yè)的因子均值和標(biāo)準(zhǔn)差(這里需要用到均值和標(biāo)準(zhǔn)差的迭代公式)。

5.? ? ?最后再對列循環(huán)計(jì)算行業(yè)中性化后的因子值,并填入結(jié)果矩陣中。

按照上述邏輯編寫代碼

以上是函數(shù)的主體運(yùn)算部分,為了放進(jìn)一張圖片里,調(diào)整了下代碼結(jié)構(gòu),可讀性不是太強(qiáng),就是按照上述的邏輯來的,各位小伙伴應(yīng)該也可以自行編寫出來。

之后咱們就用前一篇文章講的方法編譯一把,在python里運(yùn)行看看,

等了老半天才算出來,大概花了24秒的時(shí)間,其中計(jì)算的兩個(gè)矩陣都是3071*4002,就是正常日頻因子的矩陣大小。好吧這個(gè)也太慢了,我們需要改進(jìn)一下,用一下C的多線程,畢竟我的小破電腦還是有四個(gè)核的,應(yīng)該能提升下吧。

網(wǎng)上查看了幾種稍微簡便點(diǎn)的多線程計(jì)算的方法,發(fā)現(xiàn)最好用的還是openmp。

Openmp的用法極其簡單,就是在需要并行計(jì)算的for循環(huán)上加一句#pragma omp parallel for,就會(huì)對for循環(huán)中的內(nèi)容進(jìn)行并行計(jì)算。

但是如果這個(gè)for循環(huán)中的結(jié)構(gòu)相對復(fù)雜,而且for循環(huán)內(nèi)部是有執(zhí)行先后關(guān)系的,就需要用到另一個(gè)openmp的功能就是section,就是用section去包裹需要順序執(zhí)行的代碼區(qū)域。

Openmp還有一些其他的功能比如鎖呀什么的,目前代碼用不到,但是如果在并發(fā)的時(shí)候有可能對同一內(nèi)存區(qū)域進(jìn)行寫入操作,必須要上鎖,必須要上鎖,必須要上鎖?。。。ㄖ匾氖虑檎f三遍)如何上鎖的問題,之后如果遇到會(huì)進(jìn)行詳細(xì)介紹,當(dāng)前這個(gè)函數(shù)不涉及同時(shí)對一個(gè)內(nèi)存區(qū)域操作的問題。

Emm…最后代碼的樣子大概是下面這個(gè)樣子的。

對之前的代碼加上openmp并行之后,再進(jìn)行編譯,這個(gè)時(shí)候需要多加一個(gè)編譯的參數(shù),要開啟openmp這個(gè)功能,編譯代碼變成如下的樣子。

其中calc.cpp是待編譯的cpp文件,路徑1需要替換成前文獲取到的pybind11-master文件夾下的include文件夾的所在路徑,路徑2需要替換成python安裝路徑的include文件夾的所在路徑,路徑3替換成python安裝路徑下的libs文件夾的所在路徑,calc.pyd是生成的pyd名稱,需要和cpp中模塊名一致。多加了一個(gè)/openmp的參數(shù)。

然后重新編譯cpp文件,在python中運(yùn)行如下。

可以看到加openmp之后運(yùn)行時(shí)間是不加的1/3。顯著提高了運(yùn)行速度,測試電腦是4核intel處理器,可以提高三倍左右的速度。一對比發(fā)現(xiàn)快了一些,但是9秒的速度還是太慢。

好吧接下來請出大殺器intel編譯器,網(wǎng)上可以看到很多文章都說intel的編譯器很牛逼,本人就去下載了一個(gè)來試試,下載方法可以自行百度,文末也會(huì)附上本人用的intel編譯器。

本人使用的是Intel Parallel Studio XE 2019,設(shè)配的vs環(huán)境是vs2015。使用inetl編譯器需要用icl命令,不過和cl命令差不太多。編譯命令如下:

icl和cl命令的差別如下:

1.? ? ?開頭的命令從cl變成icl。

2.? ? ?從/openmp變成/Qopenmp。

3.? ? ?從link/LIBPATH(原來只需要python的lib所在的路徑) 變成了/link 對應(yīng)python的lib(這里的lib視python環(huán)境而變,本文使用的是python35所以link的是python35.lib)。

用上述命令編譯之后,在python執(zhí)行代碼如下:

其中testfunc1是初始代碼,testfunc2是加了openmp代碼后的函數(shù)??梢钥吹剿俣戎苯悠痫w,之前的什么9秒都不香了。即使是未加任何優(yōu)化的代碼,intel編譯器出來的文件執(zhí)行速度也要遠(yuǎn)遠(yuǎn)高于vs編譯器的速度。

以上就是用C給python寫相應(yīng)模塊的實(shí)操過程,用到了openmp來進(jìn)行并行計(jì)算,最后還用到了大殺器intel編譯器,真的用這個(gè)編譯器之后,其他的都不香了。

所以,小伙伴們你的行業(yè)中性計(jì)算需要多久呢?

關(guān)注【量化雜貨鋪】wx公眾號,在后臺回復(fù)【加速二】,就可以獲得Intel Parallel Studio XE 2019。希望你們的計(jì)算速度也可以起飛。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容