基于python的AI算法整合到Java Web

1、Runtime

通过命令行调用py文件,是支持多线程运行的,不会限制启动线程的数量。另一方面,数据不经过java传输给python程序,只要告诉python程序去哪个数据库读取哪一段的数据完成某种AI算法,数据由python程序自身去读取,避免无用的数据传输。并且结果直接由python返回,不再经过java,相关的参数,在调用前就已经通过java的Runtime传给python了。

String cmds = String.format("python D:\\syscall.py -f docker_percent -s 1568294220 -e 1568294230 -n openstack01 -mh %s -mp %s -mq %s -mu %s -mpd %s",
				mq_host, mq_port,queue_no+"",mq_user,mq_pwd);
// 执行CMD命令
Process pcs = Runtime.getRuntime().exec(cmds);
pcs.waitFor();

在syscall.py文件中需要使用argparse进行参数解析,才能进行这种传参的方式。

import argparse

if __name__ == "__main__":
    start = time.time()
    parser = argparse.ArgumentParser()
    parser.add_argument("-f", "--function", required=True, help="The function you want to call.")
    parser.add_argument("-s", "--start", required=True, help="The start epoch.")
    parser.add_argument("-e", "--end", help="The end epoch.")
    parser.add_argument("-n", "--hostname", required=True, help="The hostname of PC or VM or Docker.")
    parser.add_argument("-p", "--pdu", help="From which PDU.")
    parser.add_argument("-t", "--train", help="Train or not.")
    parser.add_argument("-m", "--model", help="Use which model.")
    parser.add_argument("-u", "--timeunit", help="Timeunit.")
    parser.add_argument("-mh", "--MQ_host", help="MQ_host.")
    parser.add_argument("-mp", "--MQ_port", help="MQ_port.")
    parser.add_argument("-mq", "--MQ_queue", help="MQ_queue.")
    parser.add_argument("-mu", "--MQ_user", help="MQ_user.")
    parser.add_argument("-mpd", "--MQ_pwd", help="MQ_pwd.")
    args = parser.parse_args()
    MQ_queue = args.MQ_queue
    MQ_host = args.MQ_host
    MQ_port = 61613
    MQ_user = args.MQ_user
    MQ_pwd = args.MQ_pwd
    if args.function == "from_mainsys":
        from_mainsys(args)
    elif args.function == "docker_percent":
        docker_percent(args)
    elif args.function == "pred_power":
        pred_power(args)
    elif args.function == "pcvm_power":
        pcvm_power(args)
        end = time.time()
        print(end-start)
    else:
        send_to_queue("No Such Function!")

Runtime是可以以命令行的形式运行py文件的,也支持传参和获取返回结果,但是返回结果是只能让python程序print输出结果到cmd,然后用字符流截取这个print的内容获得。Runtime其实就还是用python的环境运行python程序,所以python程序速度会快一些。但是我们需要提前在服务器配好相应的环境才可以。如果只是这样,那么这种方法是可行的,但是,在之后的测试中,出现了一些问题,主要是效率的问题。

​经过测试Runtime本地运行一个py文件需要4s(如果放到服务器上是1.5s)。其中0.7s(服务器上是0.3s)是运行服务的时间。也就是说,直接调用的话,会浪费很大的一段时间去走这个java调用python的过程。

2、Jython

Jython是一种将python编译成字节码,在JVM上运行的方式。这种方式可能比较灵活,但是速度会比较慢。

在实际使用中,遇到的第一个问题就是,使用第三方库的时候会出现一些问题,因为是直接编译成JVM字节码的,所以本地配的python环境对Jython而言是没用的,也就是说第三方包在Jython运行中都是不存在的,比如pytorch,numpy这些常用的包。最简单的一种解决方案就是,配置一个Jython的环境,将第三方包拷贝到Jython的Lib中,运行的时候将Jython的环境导进来,就可以解决这种导入第三方包的问题,但是这样就是比较麻烦了。

Jython的安装大家百度就可以,但是安装包下载很慢,有需要可以联系我。安装好Jython后,需要往Jython的Lib\site-package中添加相关的依赖包,可以直接从python的site-package中拷贝过来,并且要修改一下路径。运行的代码如下所示:

System.setProperty("python.home","E:\\jython2.7.0");
PySystemState sys = Py.getSystemState();
sys.path.add("E:\\jython2.7.0\\Lib\\site-packages");
PythonInterpreter interpreter = new PythonInterpreter();
interpreter.execfile("D:\\test\\activemq.py");

比如我这边的activemq.py中用到了与消息队列交互的stomp包,所以得往Jython的Lib\site-package中拷贝stomp的包。

import stomp

MQ_queue = "asdfasdfs"
MQ_host = "127.0.0.1"
MQ_port = 61613
MQ_user = "admin"
MQ_pwd = "admin"
def send_to_queue(msg):
    conn = stomp.Connection10([(MQ_host, MQ_port)], auto_content_length=False)
    conn.start()
    conn.connect(MQ_user, MQ_pwd, wait=True)
    conn.send(MQ_queue, msg)
    conn.disconnect()

send_to_queue("hello")

基于python的AI算法整合到Java Web_第1张图片
如果只是这个问题,其实还能用Jython,但是最大的问题是,现在的Jython版本最高是2.7.2它只支持python2,而我们的算法都是用python3写的,这就很复杂了。并且我还运行了下程序,的确还是非常耗时,Jython也不太可行。

3、打成Jar包

这是一个比较复杂的方式,但是根据某位博主Python一键转Jar包,Java调用Python新姿势!比较,性能那是杠杠的。但是也存在一些坑,可以按照这个博客python转jar进行样例的尝试。有点复杂,涉及到了Cython和JNI的东西。

你可能感兴趣的:(java,pytorch,深度学习)