Embed Python in java (jep) 환경 설정

Programming/Java 2017.04.05 01:17

Embed Python in Java (jep)


  jep는 간략하게 설명하면 java로 python interpreter를 구현하여 C / C++ 기반의 library와는 호환이 어려웠던 jython과는 다르게, JNI를 통해 CPython을 호출함으로써 C / C++ 기반의 python library도 java 상에서 실행이 가능한 프로젝트이다. 


Getting-Started 를 따라서 설치를 진행하다보면, 별도의 python library 사용 없는 간단한 python 코드의 경우 쉽게 실행 가능하다


Main.java:

import jep.Jep;

public class Main {
  public static void main(String[] args) throws Exception{
    try(Jep jep = new Jep(false)) {
      jep.eval("from java.lang import System");
      jep.eval("s = 'Hello World'");
      jep.eval("System.out.println(s)");
      jep.eval("print(s)");
      jep.eval("print(s[1:-1])");
    }
  }
}


compile 및 실행

javac -cp /usr/local/lib/python2.7/dist-packages/jep/jep-3.6.3.jar Main.java
java -cp /usr/local/lib/python2.7/dist-packages/jep/jep-3.6.3.jar:. -Djava.library.path=/usr/local/lib/python2.7/dist-packages/jep Main


실행 결과:

Hello World
Hello World
ello Worl

그러나, Numpy와 같은 외부 라이브러리를 사용하려고 하면, 다음과 같은 에러를 확인할 수 있다:

Exception in thread "main" jep.JepException: :
Importing the multiarray numpy extension module failed.  Most
likely you are trying to import a failed build of numpy.
If you're working with a numpy git repo, try `git clean -xdf` (removes all
files not under version control).  Otherwise reinstall numpy.

        at /usr/local/lib/python2.7/dist-packages/numpy/core/__init__.(__init__.py:24)
        at /usr/local/lib/python2.7/dist-packages/numpy/lib/type_check.(type_check.py:11)
        at /usr/local/lib/python2.7/dist-packages/numpy/lib/__init__.(__init__.py:8)
        at /usr/local/lib/python2.7/dist-packages/numpy/add_newdocs.(add_newdocs.py:13)
        at /usr/local/lib/python2.7/dist-packages/numpy/__init__.(__init__.py:142)

 당연히 Numpy는 정상작동 하고 있는 상태여서 왜 이런 문제가 발생할까, 어떻게 해결할까 고민했는데 문제자체는 jep 가 포함된 java를 실행할 때 환경 변수의 문제였다.

(* jep github page의 버그 리포팅을 보면 python 2.7.11 에서는 문제가 있을 수도 있으므로, 2.7.10 이나 2.7.12 혹은 더 높은 버전을 사용하는 것을 추천한다.)


다음과 같이 실행 전에 환경변수를 주면 위와 같이 library import 시 제대로 못읽어오는 문제는 해결할 수 있다:

LD_LIBRARY_PATH="/usr/lib:/usr/local/lib/python2.7/dist-packages/"; export LD_LIBRARY_PATH
LD_PRELOAD="/usr/lib/x86_64-linux-gnu/libpython2.7.so"; export LD_PRELOAD
java -cp /usr/local/lib/python2.7/dist-packages/jep/jep-3.6.3.jar:. -Djava.library.path=/usr/local/lib/python2.7/dist-packages/jep Main


참고로, LD_LIBRARY_PATH와 LD_PRELOAD에 사용하는 python library 및 so 파일의 경로는 리눅스 배포판 마다 다르다.

나와 같이 python은 잘 사용하지 않아 아무것도 모르는 상태라면, 개인적으로 numpy와 같은 library가 잘 작동하고 있는지도 확인할 겸 jep test를 진행하는것을 추천한다. 


상단의 jep의 github에서 해당 git 을 가져온 후, test를 진행해 보자:


python setup.py test


빌드 메시지들도 나오면서, 정상적으로 작동한다면 다음과 같이 끝나는 메시지를 얻을 수 있다:

$python setup.py test
numpy include found at /usr/local/lib/python2.7/dist-packages/numpy/core/include
running test
running build
running setup_java
running build_java
running build_javah
running build_jar
running build_py
running build_ext
running build_scripts
ln -sf jep.so build/lib.linux-x86_64-2.7/libjep.so
....................................................................................................................ssssssssssss......................
----------------------------------------------------------------------
Ran 150 tests in 1.869s

OK (skipped=12)

나의 경우 이미 실행을 해 빌드 메시지는 나오지 않았다.


test가 끝났다면 jep 디렉토리 내에 build 디렉토리가 생기고, build/scripts-{python.version}/jep 스크립트를 열어보면 다음과 같이 생겼다:


#!/bin/sh

VIRTUAL_ENV=
export VIRTUAL_ENV

LD_LIBRARY_PATH="/usr/lib:/usr/local/lib/python2.7/dist-packages/"; export LD_LIBRARY_PATH
LD_PRELOAD="/usr/lib/x86_64-linux-gnu/libpython2.7.so"; export LD_PRELOAD

if test "x$VIRTUAL_ENV" != "x"; then
  PATH="$VIRTUAL_ENV/bin:$PATH"
  export PATH
  PYTHONHOME="$VIRTUAL_ENV"
  export PYTHONHOME
fi

cp="/usr/local/lib/python2.7/dist-packages/jep/jep-3.6.3.jar"
if test "x$CLASSPATH" != "x"; then
    cp="$cp":"$CLASSPATH"
fi

jni_path="/usr/local/lib/python2.7/dist-packages/jep"

args=$*
if test "x$args" = "x"; then
  args="/usr/local/lib/python2.7/dist-packages/jep/console.py"
fi

exec java -classpath "$cp" -Djava.library.path="$jni_path" jep.Run $args


해당 스크립트를 참조하면 자신의 환경에서 LD_LIBRARY_PATH, LD_PRELOAD, -Djava.library.path, -classpath 에 어떤 파일 및 경로를 지정해야 하는지 쉽게 알 수 있다. 



저작자 표시 비영리 동일 조건 변경 허락
신고
Trackback 0 : Comment 0

How do I list the files inside a JAR file?

Programming/Java 2016.08.31 19:31

http://stackoverflow.com/a/28057735/6599494


spring-boot의 단일 jar 파일에서 의존성 파일을 추출해야할 일이 생겼다.


위의 글의 방법 중 CodeSource 의 경우에는 /BOOT-INF/lib 밑의 파일의 리스트를 얻어오는데 실패했지만, Java 8의 Files.walk 기능을 사용해서는 올바르게 리스트를 얻어왔고 덕분에 다이나믹하게 파일을 추출하는데 성공했다.


Java 7 이라면 Files.walkFileTree를 쓰면 되지 않을까 한다.


저작자 표시 비영리 동일 조건 변경 허락
신고
Trackback 0 : Comment 0

Performance Evaluation of In-Memory Computing on Scale-Up and Scale-Out Cluster

Cloud computing 2016.08.06 11:44

icufn.pdf


ICUFN 2016: Performance Evaluation of In-Memory Computing on Scale-Up and Scale-Out Cluster 최종 제출버전


IEEE xplore 링크: http://dx.doi.org/10.1109/ICUFN.2016.7537070 

저작자 표시 비영리 동일 조건 변경 허락
신고

'Cloud computing' 카테고리의 다른 글

Performance Evaluation of In-Memory Computing on Scale-Up and Scale-Out Cluster  (0) 2016.08.06
Kimberlize  (0) 2013.02.27
Kimberley  (0) 2013.02.26
Trackback 0 : Comment 0