JNA, JNI'ye kıyasla yerel kodu aramak için biraz daha kolay görünüyor. Hangi durumlarda JNA yerine JNI kullanırsınız?
JNA, JNI'ye kıyasla yerel kodu aramak için biraz daha kolay görünüyor. Hangi durumlarda JNA yerine JNI kullanırsınız?
Yanıtlar:
Karşılaştığım sorunlar bunlar. Belki daha fazlası vardır. Ancak genel olarak performans jna ve jni arasında o kadar da farklı değildir, bu yüzden JNA'yı nerede kullanırsanız kullanın onu kullanın.
DÜZENLE
Bu cevap oldukça popüler görünüyor. İşte bazı eklemeler:
Bu yüzden, hala mümkün olan her yerde JNA veya BridJ kullanmanın ve performans kritikse jni'ye dönmenin daha iyi olduğuna inanıyorum, çünkü yerel işlevleri sık sık çağırmanız gerekiyorsa, performans düşüşü fark edilir.
JNIEXPORT
işlevleri çağırabilir . Şu anda JNI kullanan bir seçenek olarak JavaCpp'yi araştırıyorum, ancak vanilya JNI'nin bunu desteklediğini düşünmüyorum. Göz ardı ettiğim vanilya JNI kullanarak C ++ üye işlevlerini çağırmanın bir yolu var mı?
Böyle genel bir soruyu yanıtlamak zor. Sanırım en bariz fark, JNI ile tür dönüştürme Java / yerel sınırın yerel tarafında gerçekleştirilirken, JNA ile tür dönüştürme Java'da gerçekleştirilir. C'de programlama konusunda oldukça rahat hissediyorsanız ve bazı yerel kodları kendiniz uygulamanız gerekiyorsa, JNI'nin çok karmaşık görünmeyeceğini varsayıyorum. Bir Java programcısıysanız ve yalnızca üçüncü taraf bir yerel kitaplığı çağırmanız gerekiyorsa, JNA'yı kullanmak muhtemelen JNI ile ilgili pek de açık olmayan sorunlardan kaçınmanın en kolay yoludur.
Asla herhangi bir farklılığı kıyaslamamış olsam da, tasarım nedeniyle yapardım, en azından bazı durumlarda JNA ile tip dönüşümünün JNI'den daha kötü performans göstereceğini varsayalım. Örneğin dizileri iletirken, JNA bunları her işlev çağrısının başında ve işlev çağrısının sonunda geri dönerek Java'dan yerel olana dönüştürecektir. JNI ile, dizinin yerel bir "görünümü" oluşturulduğunda kendinizi kontrol edebilirsiniz, potansiyel olarak yalnızca dizinin bir kısmının bir görünümünü oluşturabilir, görünümü birkaç işlev çağrısında tutabilir ve sonunda görünümü serbest bırakıp isteyip istemediğinize karar verebilirsiniz. değişiklikleri saklamak (potansiyel olarak verilerin geri kopyalanmasını gerektirir) veya değişiklikleri iptal etmek (kopyası gerekmez). Memory sınıfını kullanarak JNA ile işlev çağrılarında yerel bir dizi kullanabileceğinizi biliyorum, ancak bu aynı zamanda bellek kopyalamayı da gerektirecektir. JNI için gereksiz olabilir. Aradaki fark alakalı olmayabilir, ancak asıl hedefiniz uygulama performansını bazı kısımlarını yerel kodda uygulayarak artırmaksa, daha kötü performans gösteren bir köprü teknolojisi kullanmak en bariz seçenek gibi görünmüyor.
Ben ikisinin de ağır bir kullanıcısı olmasam da, sadece kafamın tepesinde bulabildiğim şey bu. Ayrıca, sağladıklarından daha iyi bir arayüz istiyorsanız, JNA'dan kaçınabileceğiniz gibi görünüyor, ancak bunun etrafında java'da kodlama yapabilirsiniz.
Bu arada, projelerimizden birinde çok küçük bir JNI ayak izi tuttuk. Etki alanı nesnelerimizi temsil etmek için protokol arabellekleri kullandık ve bu nedenle Java ve C'yi köprülemek için yalnızca bir yerel işleve sahip olduk (bu durumda C işlevi, bir dizi başka işlevi çağırırdı).
Bu doğrudan bir cevap değil ve JNA ile deneyimim yok ama JNA Kullanan Projelere baktığımda ve SVNKit, IntelliJ IDEA, NetBeans IDE gibi isimler gördüğümde, bunun oldukça iyi bir kitaplık olduğuna inanmaya meyilliyim.
Aslında, JNI'den (sıkıcı bir geliştirme süreci olan) daha basit göründüğü için, mecbur kaldığımda JNI yerine JNA kullanacağımı kesinlikle düşünüyorum. Çok kötü, JNA şu anda serbest bırakılmadı.
JNI performansı istiyorsanız, ancak karmaşıklığından korkuyorsanız, JNI bağlamalarını otomatik olarak oluşturan araçları kullanmayı düşünebilirsiniz. Örneğin, JANET (sorumluluk reddi: Ben yazdım) tek bir kaynak dosyada Java ve C ++ kodunu karıştırmanıza ve örneğin standart Java sözdizimini kullanarak C ++ 'dan Java'ya çağrı yapmanıza izin verir. Örneğin, Java standart çıktısına bir C dizesini şu şekilde yazdırabilirsiniz:
native "C++" void printHello() {
const char* helloWorld = "Hello, World!";
`System.out.println(#$(helloWorld));`
}
JANET daha sonra gömülü backtick Java'yı uygun JNI çağrılarına çevirir.
Aslında JNI ve JNA ile bazı basit kıyaslamalar yaptım.
Başkalarının da belirttiği gibi, JNA kolaylık sağlamak içindir. JNA'yı kullanırken yerel kodu derlemenize veya yazmanıza gerek yoktur. JNA'nın yerel kütüphane yükleyicisi de şimdiye kadar gördüğüm en iyi / kullanımı en kolay olanlardan biri. Ne yazık ki, JNI için kullanamazsınız öyle görünüyor. (Bu nedenle , System.loadLibrary () için JNA'nın yol kuralını kullanan ve sınıf yolundan (yani kavanozlardan) sorunsuz yüklemeyi destekleyen bir alternatif yazdım .)
Ancak JNA'nın performansı, JNI'ninkinden çok daha kötü olabilir. Basit bir yerel tamsayı artış işlevi "return arg + 1;" olarak adlandırılan çok basit bir test yaptım. Jmh ile yapılan karşılaştırmalar, bu işleve JNI çağrılarının JNA'dan 15 kat daha hızlı olduğunu gösterdi.
Yerel işlevin 4 değerden oluşan bir tamsayı dizisini topladığı daha "karmaşık" bir örnek, JNI performansının JNA'dan 3 kat daha hızlı olduğunu gösterdi. Azaltılmış avantaj muhtemelen JNI'deki dizilere nasıl eriştiğinizden kaynaklanıyordu: Örneğim bazı şeyler yarattı ve her toplama işlemi sırasında yeniden yayınladı.
Kod ve test sonuçları github adresinde bulunabilir .
Performans karşılaştırması için JNI ve JNA'yı araştırdım çünkü bunlardan birinin projede dll'yi çağırmasına karar vermemiz gerekiyordu ve gerçek zamanlı bir kısıtlamamız vardı. Sonuçlar, JNI'nin JNA'dan daha yüksek performansa sahip olduğunu göstermiştir (yaklaşık 40 kat). Belki JNA'da daha iyi performans için bir numara vardır, ancak basit bir örnek için çok yavaştır.
Bir şeyi kaçırmadığım sürece, JNA ile JNI arasındaki temel fark, JNA ile Java kodunu yerel (C) koddan çağıramazsınız değil mi?
Benim özel uygulamamda, JNI kullanımının çok daha kolay olduğunu kanıtladı. Seri bağlantı noktasından sürekli akışları okuyup yazmam gerekiyordu - başka hiçbir şey yoktu. JNA'daki çok ilgili altyapıyı öğrenmeye çalışmak yerine, Windows'ta yerel arabirimi yalnızca altı işlevi dışa aktaran özel amaçlı bir DLL ile prototiplemeyi çok daha kolay buldum: