JNA ดูเหมือนจะใช้งานง่ายกว่าเล็กน้อยในการเรียกรหัสเนทีฟเมื่อเทียบกับ JNI คุณจะใช้ JNI กับ JNA ในกรณีใดบ้าง?
JNA ดูเหมือนจะใช้งานง่ายกว่าเล็กน้อยในการเรียกรหัสเนทีฟเมื่อเทียบกับ JNI คุณจะใช้ JNI กับ JNA ในกรณีใดบ้าง?
คำตอบ:
นี่คือปัญหาที่ฉันพบ อาจจะมีมากกว่านี้ แต่โดยทั่วไปประสิทธิภาพไม่ได้แตกต่างกันระหว่าง jna และ jni ดังนั้นทุกที่ที่คุณสามารถใช้ JNA ให้ใช้
แก้ไข
คำตอบนี้ดูเหมือนจะเป็นที่นิยมมากทีเดียว ดังนั้นนี่คือส่วนเพิ่มเติมบางส่วน:
ดังนั้นฉันยังคงเชื่อว่าเมื่อใดก็ตามที่เป็นไปได้ควรใช้ JNA หรือ BridJ ดีกว่าและเปลี่ยนกลับเป็น jni หากประสิทธิภาพเป็นสิ่งสำคัญเพราะหากคุณต้องการเรียกใช้ฟังก์ชันเนทีฟบ่อยๆประสิทธิภาพจะสังเกตได้ชัดเจน
JNIEXPORT
ใช้ฟังก์ชันส่วนกลางเท่านั้น ฉันกำลังสำรวจ JavaCpp เป็นตัวเลือกซึ่งใช้ JNI แต่ฉันไม่คิดว่า vanilla JNI รองรับสิ่งนี้ มีวิธีเรียกใช้ฟังก์ชันสมาชิก C ++ โดยใช้ vanilla JNI ที่ฉันมองเห็นหรือไม่?
เป็นเรื่องยากที่จะตอบคำถามทั่วไปเช่นนี้ ฉันคิดว่าความแตกต่างที่ชัดเจนที่สุดคือเมื่อใช้ JNI การแปลงประเภทจะถูกนำไปใช้ที่ด้านเนทีฟของเส้นขอบ Java / เนทีฟในขณะที่ JNA การแปลงประเภทจะดำเนินการใน Java หากคุณรู้สึกสบายใจกับการเขียนโปรแกรมในภาษา C และต้องติดตั้งโค้ดเนทีฟด้วยตัวเองฉันคิดว่า JNI จะไม่ซับซ้อนเกินไป หากคุณเป็นโปรแกรมเมอร์ Java และจำเป็นต้องเรียกใช้ไลบรารีเนทีฟของบุคคลที่สามเท่านั้นการใช้ JNA น่าจะเป็นเส้นทางที่ง่ายที่สุดในการหลีกเลี่ยงปัญหาที่อาจไม่ชัดเจนกับ JNI
แม้ว่าฉันจะไม่เคยเปรียบเทียบความแตกต่างใด ๆ แต่ฉันก็เป็นเพราะการออกแบบอย่างน้อยก็สมมติว่าการแปลงประเภทด้วย JNA ในบางสถานการณ์จะทำได้แย่กว่ากับ JNI ตัวอย่างเช่นเมื่อส่งผ่านอาร์เรย์ JNA จะแปลงสิ่งเหล่านี้จาก Java เป็นเนทีฟที่จุดเริ่มต้นของการเรียกใช้ฟังก์ชันแต่ละครั้งและย้อนกลับเมื่อสิ้นสุดการเรียกใช้ฟังก์ชัน ด้วย JNI คุณสามารถควบคุมตัวเองได้เมื่อสร้าง "มุมมอง" ดั้งเดิมของอาร์เรย์ซึ่งอาจเป็นเพียงการสร้างมุมมองของส่วนหนึ่งของอาร์เรย์เก็บมุมมองไว้ในการเรียกใช้ฟังก์ชันต่างๆและในตอนท้ายปล่อยมุมมองและตัดสินใจว่าคุณต้องการหรือไม่ เพื่อเก็บการเปลี่ยนแปลง (อาจต้องคัดลอกข้อมูลกลับ) หรือทิ้งการเปลี่ยนแปลง (ไม่จำเป็นต้องทำสำเนา) ฉันรู้ว่าคุณสามารถใช้อาร์เรย์เนทีฟในการเรียกฟังก์ชันด้วย JNA โดยใช้คลาสหน่วยความจำ แต่สิ่งนี้จะต้องมีการคัดลอกหน่วยความจำด้วย ซึ่งอาจไม่จำเป็นกับ JNI ความแตกต่างอาจไม่เกี่ยวข้องกัน แต่หากเป้าหมายเดิมของคุณคือการเพิ่มประสิทธิภาพของแอปพลิเคชันโดยการนำบางส่วนมาใช้ในโค้ดเนทีฟการใช้เทคโนโลยีบริดจ์ที่มีประสิทธิภาพแย่กว่าดูเหมือนจะไม่ใช่ทางเลือกที่ชัดเจนที่สุด
นั่นเป็นเพียงสิ่งเดียวที่ฉันสามารถคิดขึ้นมาได้แม้ว่าฉันจะไม่ใช่คนใช้งานหนักก็ตาม ดูเหมือนว่าคุณอาจหลีกเลี่ยง JNA หากคุณต้องการอินเทอร์เฟซที่ดีกว่าที่มีให้ แต่คุณสามารถเขียนโค้ดใน java ได้
อย่างไรก็ตามในหนึ่งในโครงการของเราเราเก็บภาพพิมพ์ JNI ขนาดเล็กมาก เราใช้โปรโตคอลบัฟเฟอร์เพื่อแสดงอ็อบเจ็กต์โดเมนของเราดังนั้นจึงมีฟังก์ชันเนทีฟเพียงฟังก์ชันเดียวในการเชื่อมโยง Java และ C (แน่นอนว่าฟังก์ชัน C จะเรียกฟังก์ชันอื่น ๆ อีกมากมาย)
มันไม่ใช่คำตอบโดยตรงและฉันไม่มีประสบการณ์กับ JNA แต่เมื่อฉันดูโครงการที่ใช้ JNAและเห็นชื่อเช่น SVNKit, IntelliJ IDEA, NetBeans IDE ฯลฯ ฉันมักจะเชื่อว่ามันเป็นห้องสมุดที่ดีทีเดียว
จริงๆแล้วฉันคิดว่าฉันจะใช้ JNA แทน JNI เมื่อฉันต้องใช้มันดูง่ายกว่า JNI (ซึ่งมีกระบวนการพัฒนาที่น่าเบื่อ) เสียดายที่ตอนนี้ JNA ไม่ได้เปิดตัว
หากคุณต้องการประสิทธิภาพของ JNI แต่กังวลกับความซับซ้อนคุณอาจพิจารณาใช้เครื่องมือที่สร้างการเชื่อม JNI โดยอัตโนมัติ ตัวอย่างเช่นJANET (ข้อจำกัดความรับผิดชอบ: ฉันเขียนไว้) ช่วยให้คุณสามารถผสมโค้ด Java และ C ++ ในซอร์สไฟล์เดียวและเช่นโทรจาก C ++ ไปยัง Java โดยใช้ไวยากรณ์ Java มาตรฐาน ตัวอย่างเช่นต่อไปนี้เป็นวิธีพิมพ์สตริง C ไปยังเอาต์พุตมาตรฐาน Java:
native "C++" void printHello() {
const char* helloWorld = "Hello, World!";
`System.out.println(#$(helloWorld));`
}
จากนั้น JANET จะแปล Java ที่ฝังแบ็กทิกเป็นการเรียก JNI ที่เหมาะสม
จริงๆแล้วฉันทำเกณฑ์มาตรฐานง่ายๆกับ JNI และ JNA
ดังที่คนอื่น ๆ ชี้ให้เห็นแล้ว JNA มีไว้เพื่อความสะดวก คุณไม่จำเป็นต้องคอมไพล์หรือเขียนโค้ดเนทีฟเมื่อใช้ JNA ตัวโหลดไลบรารีดั้งเดิมของ JNA ยังเป็นหนึ่งในตัวโหลดที่ดีที่สุด / ง่ายที่สุดที่ฉันเคยเห็น น่าเศร้าที่คุณไม่สามารถใช้กับ JNI ได้ (นั่นเป็นเหตุผลที่ฉันเขียนทางเลือกสำหรับ System.loadLibrary ()ที่ใช้รูปแบบเส้นทางของ JNA และรองรับการโหลดอย่างราบรื่นจาก classpath (เช่น jars))
อย่างไรก็ตามประสิทธิภาพของ JNA อาจแย่กว่า JNI มาก ฉันได้ทำการทดสอบอย่างง่าย ๆ ซึ่งเรียกว่าฟังก์ชันการเพิ่มจำนวนเต็มเนทีฟอย่างง่าย "return arg + 1;" Benchmarks ที่ทำด้วย jmh แสดงให้เห็นว่า JNI เรียกใช้ฟังก์ชันนั้นเร็วกว่า JNA 15 เท่า
ตัวอย่างที่ "ซับซ้อน" มากขึ้นซึ่งฟังก์ชันเนทีฟจะรวมอาร์เรย์จำนวนเต็ม 4 ค่ายังคงแสดงให้เห็นว่าประสิทธิภาพของ JNI เร็วกว่า JNA 3 เท่า ข้อได้เปรียบที่ลดลงอาจเป็นเพราะคุณเข้าถึงอาร์เรย์ใน JNI ได้อย่างไร: ตัวอย่างของฉันได้สร้างบางสิ่งและปล่อยออกมาอีกครั้งในระหว่างการดำเนินการสรุปแต่ละครั้ง
รหัสและผลการทดสอบสามารถพบได้ที่ GitHub
ฉันตรวจสอบ JNI และ JNA เพื่อเปรียบเทียบประสิทธิภาพเพราะเราจำเป็นต้องตัดสินใจหนึ่งในนั้นเพื่อเรียก dll ในโครงการและเรามีข้อ จำกัด ด้านเวลาจริง ผลการวิจัยพบว่า JNI มีประสิทธิภาพมากกว่า JNA (ประมาณ 40 เท่า) อาจมีเคล็ดลับสำหรับประสิทธิภาพที่ดีขึ้นใน JNA แต่มันช้ามากสำหรับตัวอย่างง่ายๆ
เว้นแต่ฉันจะขาดอะไรไปความแตกต่างหลักระหว่าง JNA กับ JNI กับ JNA คุณไม่สามารถเรียกโค้ด Java จากโค้ดเนทีฟ (C) ได้หรือไม่?
ในแอปพลิเคชันเฉพาะของฉัน JNI พิสูจน์แล้วว่าใช้งานง่ายกว่ามาก ฉันจำเป็นต้องอ่านและเขียนสตรีมแบบต่อเนื่องไปยังและจากพอร์ตอนุกรม - และไม่มีอะไรอื่น แทนที่จะพยายามเรียนรู้โครงสร้างพื้นฐานที่เกี่ยวข้องใน JNA ฉันพบว่าการสร้างต้นแบบอินเทอร์เฟซเนทีฟใน Windows นั้นง่ายกว่ามากด้วย DLL วัตถุประสงค์พิเศษที่ส่งออกเพียงหกฟังก์ชัน: