我在c中使用了一些快速通信库,但我的应用程序的其余部分是用Java编写的。所以我想将收到的数据传递给我的java应用程序。
作为测试,我每隔5ms收到1000次消息。 这导致发件人应用程序完成发送时。接收器应用程序仍需要时间来处理数据。
如果我删除该行
(*g_env)->CallVoidMethod(g_env, store_callback, methodHandleMessage, top,
ts, fo, msg);
接收方应用程序在发送方发送完最后一条消息后立即完成。
有没有机会加快速度?
void onMessageReceived(char* topic, char* timestamp, char* format,
char* message) {
JNIEnv * g_env;
int getEnvStat = (*g_vm)->GetEnv(g_vm, (void **) &g_env,
JNI_VERSION_1_8);
if (getEnvStat == JNI_EDETACHED) {
if ((*g_vm)->AttachCurrentThread(g_vm, (void **) &g_env, NULL) != 0) {
puts("Failed to attach");
fflush(stdout);
}
}
if (methodHandleMessage) {
} else {
jclass clazz = (*g_env)->GetObjectClass(g_env, store_callback);
methodHandleMessage =
(*g_env)->GetMethodID(g_env, clazz, "handleMessage",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
}
jstring top = (*g_env)->NewStringUTF(g_env, topic);
jstring ts = (*g_env)->NewStringUTF(g_env, timestamp);
jstring fo = (*g_env)->NewStringUTF(g_env, format);
jstring msg = (*g_env)->NewStringUTF(g_env, message);
//This line takes too long!
(*g_env)->CallVoidMethod(g_env, store_callback, methodHandleMessage, top,
ts, fo, msg);
}
答案 0 :(得分:0)
您可以通过将类标记为handleMessage
来节省final
调用的一些时间,这将消除执行虚拟查找的需要。
如果这还不够,并且如果不需要异步调用handleMessage
,则可以避免直接调用它,而是将参数存储在您将创建和管理的本地C数组中。然后,您可以通过MonitorEnter
锁定它,调用GetMethodID(g_env, clazz, "notify", "()V")
,然后使用MonitorExit
解锁来通知Java对象有可用的数据。
然后在Java方面,store_callback
实例将有一个等待通知的专用线程,如下所示:
while (true) {
synchronized (self) {
wait();
// we were informed that we received new data: now pull it out and process
String[][] args = getBufferedArgumentsViaJNI();
for (String[] arg : args) {
handleMessage(arg[0], arg[1], arg[2], arg[3]);
}
}
}
回到原生的一面,你需要实现getBufferedArgumentsViaJNI
来返回并清除所有缓冲参数的JNI数组(作为练习留给读者)。
作为一个精明的读者,您可能想知道为什么这会更快,因为您仍然需要在onMessageReceived
中调用JNI方法以及执行JNI同步,因此它仍然会产生JNI开销。答案是,虽然我无法保证消息处理总体上更快,但“等待”调用可能会明显加快,因为wait()
在我见过的每个JVM上作为本机方法实现
答案 1 :(得分:0)
java方法可能为空,但您每次仍调用GetEnv(),并创建4个可复制到Java的字符串。这些字符串有多大?我试着用一些10-20个字符的字符串调用这个方法并测量它。另一个简单的解决方案(如果方法调用非常慢)用数组而不是字符串调用它,甚至可能将几个字符串打包到一个数组中。或者您也可以使用共享缓冲区(http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/functions.html#GetDirectBufferAddress)