java通过c调用python

来源:互联网 发布:手机用户mac绑定错误 编辑:程序博客网 时间:2024/06/06 02:08

最近在做一个项目,主要是用到python下的一个库(sympy),之前通过java通过jython调用python,速度达不到要求,后面把python单独拿出来,做成一个本地服务,通过socket与java通信,速度上去了,但是很不方便

现在是通过c调用python,然后利用java调用c(这方面的资料网上很多,下面主要说说细节问题)

1,因为java调用c,要是使用64位,所以对应的python必须下载64位版的,

2,然后在vs生成dll文件的时候,要设置为64位,我是用vs2010写的



3.注意引入python的库文件和头文件




生成dll的工程:




下面是头文件 mydll.h代码

#ifndef _MYDLL_H_#define _MYDLL_H_#include <string>#include <stdio.h>#include <stdlib.h>#include <sstream>#include "jni.h"#ifdef __cplusplusextern "C" {#endifJNIEXPORT jstring JNICALL Java_sympy_SympyJavaJNI_invokingSympy__Ljava_lang_String_2Ljava_lang_String_2  (JNIEnv *, jobject, jstring, jstring);JNIEXPORT jstring JNICALL Java_sympy_SympyJavaJNI_invokingSympy__Ljava_lang_String_2Ljava_lang_String_2Ljava_lang_String_2  (JNIEnv *, jobject, jstring, jstring, jstring);#ifdef __cplusplus}#endif#endif //_MYDLL_H_
注:jni.h是Jni自动生成的,奇怪的东西是jni自动生成的,直接复制过来用就是了,这里主要定义了2个接口函数,第一个参数是对应python里面的函数名,第二个参数和第三个函数是该对应函数的参数,(如果该函数只要1个参数,就是调用的第一个,利用函数重载完成),


testdlladd.cpp代码清淡,主要是实现上面的2个接口(我承认我的文件命名很奇怪)

注释中的Add函数就是c调用python中的东西,其中pDict是全局变量,后面会提到

// testdlladd.cpp : 定义 DLL 应用程序的导出函数。//#include "stdafx.h"#include "mydll.h"using namespace std;string int2str(int &);/*char* Add(char* a, char* b){printf("pDict:%d\n",pDict);PyObject *pFunc, *pArgs, *pRetVal;    pFunc = PyDict_GetItemString(pDict, "add");    if ( !pFunc||!PyCallable_Check(pFunc) )    {        printf("can't find function [add]");        getchar();        return 0;    }    // 参数进栈    pArgs = PyTuple_New(2);    // PyObject* Py_BuildValue(char *format, ...)    // 把C++的变量转换成一个Python对象。当需要从    // C++传递变量到Python时,就会使用这个函数。此函数    // 有点类似C的printf,但格式不同。常用的格式有    // s 表示字符串,    // i 表示整型变量,    // f 表示浮点数,    // O 表示一个Python对象。//string a = int2str(plus1);//string b= int2str(plus2);    PyTuple_SetItem(pArgs, 0, Py_BuildValue("s",a)); PyTuple_SetItem(pArgs, 1, Py_BuildValue("s",b));     // 调用Python函数    pRetVal = PyObject_CallObject(pFunc, pArgs);char* res=PyString_AsString(pRetVal);     return res;}*/JNIEXPORT jstring JNICALL Java_sympy_SympyJavaJNI_invokingSympy__Ljava_lang_String_2Ljava_lang_String_2  (JNIEnv *env, jobject _obj, jstring funcName, jstring param1)  {      const char* fName = env->GetStringUTFChars(funcName,0);      const char* parameter = env->GetStringUTFChars(param1,0);      PyObject *pFunc, *pArgs, *pRetVal;      pFunc = PyDict_GetItemString(pDict, fName);      if ( !pFunc||!PyCallable_Check(pFunc) )      {          printf("can't find function %s",fName);          return 0;      }    // 参数进栈      pArgs = PyTuple_New(1);    // PyObject* Py_BuildValue(char *format, ...)    // 把C++的变量转换成一个Python对象。当需要从    // C++传递变量到Python时,就会使用这个函数。此函数    // 有点类似C的printf,但格式不同。常用的格式有    // s 表示字符串,    // i 表示整型变量,    // f 表示浮点数,    // O 表示一个Python对象。//string a = int2str(plus1);//string b= int2str(plus2);      PyTuple_SetItem(pArgs, 0, Py_BuildValue("s",parameter));//PyTuple_SetItem(pArgs, 1, Py_BuildValue("s",b));    // 调用Python函数      pRetVal = PyObject_CallObject(pFunc, pArgs);  char* res=PyString_AsString(pRetVal);      env->ReleaseStringUTFChars(funcName,fName);      env->ReleaseStringUTFChars(param1,parameter);      return env->NewStringUTF(res);  }  JNIEXPORT jstring JNICALL Java_sympy_SympyJavaJNI_invokingSympy__Ljava_lang_String_2Ljava_lang_String_2Ljava_lang_String_2  (JNIEnv * env, jobject _obj, jstring funcName, jstring param1, jstring param2)  {      const char* fName = env->GetStringUTFChars(funcName,0);      const char* p1 = env->GetStringUTFChars(param1,0);      const char* p2 = env->GetStringUTFChars(param2,0);      PyObject *pFunc, *pArgs, *pRetVal;      pFunc = PyDict_GetItemString(pDict, fName);      if ( !pFunc||!PyCallable_Check(pFunc) )      {          printf("can't find function %s",fName);          return 0;      }    // 参数进栈      pArgs = PyTuple_New(2);    // PyObject* Py_BuildValue(char *format, ...)    // 把C++的变量转换成一个Python对象。当需要从    // C++传递变量到Python时,就会使用这个函数。此函数    // 有点类似C的printf,但格式不同。常用的格式有    // s 表示字符串,    // i 表示整型变量,    // f 表示浮点数,    // O 表示一个Python对象。      PyTuple_SetItem(pArgs, 0, Py_BuildValue("s",p1));  PyTuple_SetItem(pArgs, 1, Py_BuildValue("s",p2));    // 调用Python函数      pRetVal = PyObject_CallObject(pFunc, pArgs);  char* res=PyString_AsString(pRetVal);      env->ReleaseStringUTFChars(funcName,fName);      env->ReleaseStringUTFChars(param1,p1);      env->ReleaseStringUTFChars(param2,p2);      return env->NewStringUTF(res);  }string int2str(int &i) {string s;stringstream ss(s);ss << i;return ss.str();}




stdafx.h文件代码清单

这里定义了3个全局变量,主要是因为我们要频繁调用python里的库(1秒估计要几百次吧,还没考虑高并发),所以第一次加载的时候,先把DLL文件加载的里面,避免每次调用python的时候,都去加载那个dll文件,效率就十分十分十分十分的慢

#ifndef _STDAFX_H_#define _STDAFX_H_#include "targetver.h"#define WIN32_LEAN_AND_MEAN             //  从 Windows 头文件中排除极少使用的信息// Windows 头文件:#include <windows.h>#include<stdio.h>#include "jni.h"#include "jni_md.h"#include <Python.h>extern PyObject *pDict,*pName,*pModule;#endif



下面是dllmain.cpp,dll的入口函数,我觉得该写个destroy函数

// dllmain.cpp : 定义 DLL 应用程序的入口点。#include "stdafx.h"PyObject *pDict=NULL;PyObject *pName=NULL;PyObject *pModule=NULL;static int init(void){<span style="white-space:pre"></span>// 初始化Python    //在使用Python系统前,必须使用Py_Initialize对其    //进行初始化。它会载入Python的内建模块并添加系统路    //径到模块搜索路径中。这个函数没有返回值,检查系统    //是否初始化成功需要使用Py_IsInitialized。<span style="white-space:pre"></span>    Py_Initialize();    // 检查初始化是否成功    if ( !Py_IsInitialized() )     {<span style="white-space:pre"></span>printf("Py_Initialize()  error");        return 0;    }    // 载入名为pytest的脚本(注意:不是pytest.py)    pName = PyString_FromString("sympyInvoke");    pModule = PyImport_Import(pName);    if ( !pModule )    {        printf("can't find pytest.py");        return 0;    }    pDict= PyModule_GetDict(pModule);    if ( !pDict )     {<span style="white-space:pre"></span><span style="white-space:pre"></span>printf("can't find Method!!");        return 0;    } <span style="white-space:pre"></span>}BOOL APIENTRY DllMain( HMODULE hModule,                       DWORD  ul_reason_for_call,                       LPVOID lpReserved<span style="white-space:pre"></span> ){<span style="white-space:pre"></span> <span style="white-space:pre"></span>switch (ul_reason_for_call)<span style="white-space:pre"></span>{<span style="white-space:pre"></span>case DLL_PROCESS_ATTACH:init();printf("DLL in");break; <span style="white-space:pre"></span>case DLL_THREAD_ATTACH:<span style="white-space:pre"></span>case DLL_THREAD_DETACH:<span style="white-space:pre"></span>case DLL_PROCESS_DETACH:printf("DLL out");break;<span style="white-space:pre"></span>}<span style="white-space:pre"></span>return TRUE;}


至于Jni,怎么调用这个dll,网上一查一大堆,就不在赘述了!

这样生成的dll文件就可以用在我们的java工程中去啦!(注意要安装python64位)

0 0
原创粉丝点击