2016-04-06 27 views
2

我一直在使用py4j來建立一個用戶友好的Python庫,用戶友好的Java庫。大多數情況下,這是一件輕而易舉的事情,py4j一直是一個偉大的工具。不過,在Python和Java之間發送矩陣時遇到了一些障礙。使用py4j將矩陣從Python發送到Java,如int [] [] arrays

具體而言,我有在Java靜態函數接受,作爲其自變量的整數矩陣:

public class MyClass { 
    // ... 
    public static MyObject create(int[][] matrix) { 
     // ... 
    } 
} 

我想能夠從Py4j像這樣調用此:

def create_java_object(numpy_matrix): 
    # <code here checks that numpy_matrix is a (3 x n) integer matrix> 
    # ... 
    return java_instance.jvm.my.namespace.MyClass.create(numpy_matrix) 

這不起作用,這並不令人感到意外,如果numpy_matrix被轉換爲純Python列表的列表,它也不會工作。我所預料的是,解決辦法是構造一個Java陣列和相對於現有的功能調用傳送數據:現在

def create_java_object(numpy_matrix): 
    # <code here checks that numpy_matrix is a (3 x n) integer matrix> 
    # ... 
    java_matrix = java_instance.new_array(java_instance.jvm.int, 3, n) 
    for i in range(numpy_matrix.shape[1]): 
     java_matrix[0][i] = int(numpy_matrix[0, i]) 
     java_matrix[1][i] = int(numpy_matrix[1, i]) 
     java_matrix[2][i] = int(numpy_matrix[2, i]) 
    return java_instance.jvm.my.namespace.MyClass.create(java_matrix) 

,此代碼正確運行。但是,它需要大約兩分鐘運行。順便說一下,我正在使用的矩陣約爲(3 x〜300,000)個元素。

在Py4j中有沒有一種規範的方法可以實現,它不需要很多時間來轉換矩陣?我不介意花一兩秒鐘,但這太慢了。如果沒有爲這種通信設置Py4j,是否有Python的Java互操作庫?

注意:Java庫將int[][]矩陣視爲不可變數組;即它從不試圖修改它。

回答

3

我找到了適用於這種特殊情況的解決方案;雖然它不是非常優雅:

Py4j支持高效地將Python bytearray對象作爲byte[]數組傳遞給Java。我通過修改原始庫和我的Python代碼解決了這個問題。

新的Java代碼:

public class MyClass { 
    // ... 
    public static MyObject create(int[][] matrix) { 
     // ... 
    } 
    public static MyObject createFromPy4j(byte[] data) { 
     java.nio.ByteBuffer buf = java.nio.ByteBuffer.wrap(data); 
     int n = buf.getInt(), m = buf.getInt(); 
     int[][] matrix = new int[n][m]; 
     for (int i = 0; i < n; ++i) 
     for (int j = 0; j < m; ++j) 
      matrix[i][j] = buf.getInt(); 
     return MyClass.create(matrix); 
    } 
} 

新的Python代碼:

def create_java_object(numpy_matrix): 
    header = array.array('i', list(numpy_matrix.shape)) 
    body = array.array('i', numpy_matrix.flatten().tolist()); 
    if sys.byteorder != 'big': 
     header.byteswap() 
     body.byteswap() 
    buf = bytearray(header.tostring() + body.tostring()) 
    return java_instance.jvm.my.namespace.MyClass.createFromPy4j(buf) 

這將運行在幾秒鐘,而不是幾分鐘。

+0

這隻適用於2D矩陣?如何將形狀長度存儲爲第一個值,以便您可以發送任何形狀的矩陣? – crockpotveggies