最近團隊在作代碼移植,將C++代碼用scala實現服務端的矩陣算法,作到最後一步發現C++的文件壓縮是直接調用python腳原本實現的,本着一致性的原則,文件壓縮也用scala來實現。可是測試的時候發現,這個壓縮效率跟調用python執行相差太大了,2G的txt格式文件,用scala實現壓縮用了將近200秒,可是用python只須要大約40秒,有點接受不了,反正團隊最近的故事也不多,因而研究了一下。
python
其實,scala調用python腳本是很是簡單,首先導入包算法
import scala.sys.process._
而後只須要執行一行命令便可:測試
"python /home/test.py args" ! //test.py是須要執行的Python腳本,args:Python須要的參數
這條命令是能夠直接在安裝scala環境下執行的this
可是,如今出現了一個問題,由於上面的python腳本要加上路徑,而咱們的工程全部的資源都要打包成 jar 放在 集羣環境執行的。那麼,咱們這個這個腳本應該放在哪裏才能讓python 找到來解析執行呢?想了兩種解決方案scala
第一,腳本跟jar包分離,給一個固定的路徑,而後在命令中將路徑寫死。這樣的話,須要另外安裝腳原本上次這個壓縮腳本,並且,發佈版本涉及的工程太多了,不一樣部門不一樣團隊的,並且本身也不瞭解發佈涉及的全部安裝腳本。搞很差這個功能分分鐘出問題啊,這種方法是不可行的。code
第二,將這個腳本放在咱們團隊的工程下面,跟隨其餘代碼一塊打包,這樣的話就比較容易控制了。可是,打包成 jar 後,Python是解析不到 jar 裏面的文件的。思考了一下,找到了一種方法:資源
在代碼中,找到腳本在 jar裏面的位置,而後將文件流讀取出來,寫到一個本地的路徑下,這樣,python解析器就能找到腳本的位置啦。貌似能夠,因而立馬敲代碼驗證:get
上代碼:string
def CompressFiles(){ val fileInjar = "/CompressFile.py" //打包後,能夠查看這個腳本在jar的相對路徑(個人是存放在根目錄) val in = this.getClass.getResourceAsStream(fileInjar) //獲取腳本InputStream //獲取jar所在的集羣路徑 val jarPath = this.getClass.getProtectionDomain.getCodeSource.getLocation.getPath.replace("\\","/") val pyDir = jarPath.substring(0,jarPath.lastIndexOf("/"))+"CompressFile.py" if(in != null){ val f = new File(pyDir) if (!f.exists()) f.mkdirs val localFile = pyDir +"CompressFile.py" val out = new FileOutputStream(localFile) val buf = new Array[Byte](1024) try { var nLen = in.read(buf) while(nLen != -1){ out.write(buf,0,nLen) nLen = in.read(buf) } }catch { case e:Exception => log.error(e.getMessage) case _ => log.error("Read CompressFile.py Exception") }finally{ in.close out.close } //以上代碼即可以將jar裏面的腳本寫入到了jar包所在集羣裏面的某臺機器的本地路徑了,這就爽了, //Python能夠找到腳本解析啦啦啦啦,,這樣只要把scala那條命令執行就好了 val para = "args" s"python $localFile $para" ! //para參數 }else{ log.error("a NULL error occurred when Read CompressFile.py in jar,maybe the path is invalid!") } }
至此,調用完成。
it