IT|軟體|程式語言|Java 調用 Python 使用 Jpython

極少數時候,我們會碰到類似這樣的問題:與A合作寫代碼,A只會寫Python,不熟悉Java,而你只會寫Java不擅長Python,並且發現難以用Java來重寫對方的代碼,這時,就不得不想方設法「調用對方的代碼」。
 
下面舉一些簡單的小例子,借此說明:如何在Java中調用Python代碼。
 
Maven 使用 Jpython
<dependency>
    <groupId>org.python</groupId>
    <artifactId>jython-standalone</artifactId>
    <version>2.7.1</version>
</dependency>
 
HelloPython 程式
import org.python.util.PythonInterpreter;

public class HelloPython {
    public static void main(String[] args) {
        PythonInterpreter interpreter = new PythonInterpreter();
        interpreter.exec("print('hello')");
    }
}
什麼是PythonInterpreter呢?它的中文意思即「Python解釋器」。我們知道Python程序都是通過解釋器執行的,上面的代碼就是在JVM中創建一個「Python解釋器」對象,模擬Python解釋器的行為,通過exec(” Python語句”)直接在JVM中執行Python代碼,代碼的輸出結果為:hello,需要提醒各位的是,該程序運行速度相較正常的Java or Python程序都要慢那麼一點。
 
JVM 中執行 Python 腳本
interpreter.execfile("D:/labs/mytest/hello.py");
如上,將exec改為execfile就可以了。需要注意的是,這個.py文件不能含有第三方模塊,因為這個「Python腳本」最終還是在JVM環境下執行的(而非依賴於本地計算機環境),如果.py程序中有用到第三方模塊(例如NumPy)將會報錯:java ImportError: No module named xxx
 
在JVM中調用Python編寫的函數
def hello():
    return 'Hello'
 
在Java代碼中調用這個Python函數:
import org.python.core.PyFunction;
import org.python.core.PyObject;
import org.python.util.PythonInterpreter;

public class HelloPython {
    public static void main(String[] args) {
        PythonInterpreter interpreter = new PythonInterpreter();
        interpreter.execfile("D:/labs/hello.py");

        PyFunction pyFunction = interpreter.get("hello", PyFunction.class); // 第一個參數為期望獲得的函數(變量)的名字,第二個參數為期望返回的對象類型
        PyObject pyObject = pyFunction.__call__(); // 調用函數

        System.out.println(pyObject);
    }
}
上面的代碼執行結果為:Hello
即便只是調用一個函數,也必須先加載這個.py文件,之後再通過Jython包中所定義的類獲取、調用這個函數。
 
如果函數需要參數,在Java中必須先將參數轉化為對應的「Python類型」,例如:
__call__(new PyInteger(a), new PyInteger(b))
a,b的類型均為Java中的int型,還有一些Jython類型諸如:PyString(String string)、PyList(Iterator<PyObject> iter)等,詳細信息可以參考官方的api文檔。
 
在本地環境中調用Python腳本
由於Jython運行過慢並且不支持第三方的Python模塊,通過Java代碼執行一段終端命令來調用Python腳本,根據具體問題決定如何交互可能才是實際中真正會用到的方式(詳見下面的舉例代碼)。
舉例代碼:下面是和捨友合作寫的一個小程序(可以識別很粗的手寫數字),界面上引用了core java上的一段代碼:
import java.io.*;

class PyCaller {
    private static final String DATA_SWAP = "temp.txt";
    private static final String PY_URL = System.getProperty("user.dir") + "\\test.py";

    public static void writeImagePath(String path) {
        PrintWriter pw = null;
        try {
            pw = new PrintWriter(new FileWriter(new File(DATA_SWAP)));
        } catch (IOException e) {
            e.printStackTrace();
        }

        pw.print(path);
        pw.close();
    }

    public static String readAnswer() {
        BufferedReader br;
        String answer = null;
        try {
            br = new BufferedReader(new FileReader(new File(DATA_SWAP)));
            answer = br.readLine();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return answer;
    }

    public static void execPy() {
        Process proc = null;
        try {
            proc = Runtime.getRuntime().exec("python " + PY_URL);
            proc.waitFor();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    // 測試碼
    public static void main(String[] args) throws IOException, InterruptedException {
        writeImagePath("D:\\labs\\mytest\\test.jpg");
        execPy();
        System.out.println(readAnswer());
    }
}
運行流程:Java Swing界面接收用戶輸入–> Java將用戶輸入寫到本地文件中–> Java調用本地Python腳本–> Python從本地文件拿到用戶輸入–> Python處理用戶輸入得到最終結果–> Python把最終結果寫到本地文件–> Java對Python腳本的調用結束–> Java從本地文件中取出最終結果–> Java把最終結果返回給用戶
 
 
[參考資源]

 
 
 

IT|軟體|測試|JMeter 自動生成測試報告

Jmeter 簡介

JMeter 是 Apache 組織下一套百分之百由 Java 來開發的 open source 軟體,主要設計用來測試軟體行為在負載較重的情況下是否能夠正常運作且不出錯,以及測量軟體在給定負載量(or給定壓力)下的效能表現。
 
 
Jmeter 自動化測試

Jmeter 可根據設定好的測試計畫(jmx)來執行測試。執行測試後,產生 Jmeter 測試結果(jtl)。最後根據 Jmeter 測試結果(jtl),來產生測試報告(網頁)。
 
自動生成測試報告,可分為兩種:
  1. 全新產生:jmeter 測試結果(xx.jtl) 以及測試報告路徑(xx\resultReport\)不可存在,否則 Jmeter 會執行失敗。
  2. 結合先前的 Jmeter 測試結果(jtl),產生這次的測試報告
 
 
# 全新產生本次測試報告
jmeter -n -t test.jmx -l result.jtl -e -o /tmp/ResultReport
 
說明:
  • -n: 非GUI模式執行 JMeter
  • -t: 執行測試檔所在的位置
  • -l: 指定生成測試結果的保存檔,jtl 檔案格式
  • -e: 測試結束後,生成測試報告
  • -o: 指定測試報告的存放位置
 
注意:-l -o 指定的檔及資料夾,必須不存在,否則執行會失敗
 
寫好的 bat 內容:
set _jmeter_root=C:\lab\400\apache-jmeter-3.1
For /f "tokens=1-4 delims=- " %%a in ('date /t') do (set _thisdate=%%a%%b%%c)
For /f "tokens=1-2 delims=/:" %%a in ('time /t') do (set _thisTime=%%a%%b)
set _jmeter_resultReport_root=%_jmeter_root%\bin\tmp\ResultReport_%_thisdate%_%_thisTime%
%_jmeter_root%\bin\jmeter.bat -n  -t %_jmeter_root%\bin\tmp\02.jmx -l %_jmeter_root%\bin\tmp\%_thisdate%_%_thisTime%.jtl -e -o %_jmeter_resultReport_root%
其中:
1.%_jmeter_root%\bin\tmp\02.jmx:是預先設定好的測試規劃(測試腳本、測試劇本…)
2.將 jmeter 測試結果(yyyymmdd_HHMM.jtl)統一放在 …\bin\tmp 中
3.測試報告統一放在 …\bin\tmp\ResultReport_yyyymmdd_HHMM 資料夾,擇一打開資料夾內的 index.html 後就是該測試報告
 
 
 
[後續]
  1. Jmeter 測試計畫檔(xxx.jmx)可以集中放置於某資料夾中集中處理
  2. 重新規劃下 Jmeter 測試結果(xxx.jtl) 和 jmeter 測試報告(xxx\ResultReport_yyyymmdd_HHMM) 的根目錄(不要是 bin\tmp)
  3. 若可以,即可在 win 端設定好 jmx,FTP 上傳至 server 上就可。然後再 server 上再根據 crontab 去定期執行相關 shell,就可以定期得到測試報告。
  4. 待研究 Jmeter 測試報告的各項指標含意,以及 Jmeter 測試計畫檔的各項設定
 
大功告成!