Я пишу webapp, используя Play Framework 2.1, который использует библиотеки OpenCV (2.4.6). У меня не было никаких проблем с компиляцией OpenCV и получением окончательного.jar, но есть одно замечание, которое меня беспокоит в учебнике Java/Scala для OpenCV:
Обратите внимание на вызов в
System.loadLibrary(Core.NATIVE_LIBRARY_NAME)
. Эта команда должна выполняться ровно один раз на Java-процесс до использования любых собственных методов OpenCV. Если вы его не назовете, вы получите ошибки UnsatisfiedLink. Вы также получите ошибки, если попытаетесь загрузить OpenCV, когда он уже был загружен.
Я знаю, что Play Framework многопоточен, и потоки повторно используются между запросами. Есть ли способ вызвать функцию loadLibrary
когда loadLibrary
отдельные потоки? Или я не понимаю, как работает пул потоков, и я должен загрузить библиотеку один раз за запрос? Каков правильный подход?
[Edit:] Я понял, что могу поместить код System.loadLibrary
в глобальный класс конфигурации, который заставит все потоки совместно использовать библиотеку. Библиотека не является потокобезопасной, поэтому я думаю, что это просто несчастный случай, когда я это сделаю...
Кажется, что не проблема - "Эта команда должна выполняться ровно один раз на Java- процесс " - достаточно будет назвать ее один раз при запуске приложения, и вам не нужно беспокоиться о разных потоках.
Бонус: можно проверить, была ли уже загружена библиотека (даже если она абсолютно не нужна), то есть:
def loadedLibs: Seq[String] = {
val libs = classOf[ClassLoader].getDeclaredField("loadedLibraryNames")
libs.setAccessible(true)
import scala.collection.JavaConverters._
libs.get(ClassLoader.getSystemClassLoader())
.asInstanceOf[java.util.Vector[String]]
.asScala
}
def loadOpenCVOnDemand(): Unit = {
val isLoaded = loadedLibs.map(str => str contains "opencv").reduce((x, y) => x || y)
if(!isLoaded) {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME)
}
}
Еще одна проблема заключается в том, что функции родной библиотеки можно вызывать одновременно. В OpenCV это не проблема:
Текущая реализация OpenCV полностью повторима. То есть, одна и та же функция, один и тот же константный метод экземпляра класса или один и тот же непостоянный метод из разных экземпляров класса может вызываться из разных потоков. Кроме того, тот же cv :: Mat может использоваться в разных потоках, потому что операции подсчета ссылок используют атомарные инструкции, специфичные для архитектуры.