调用 Java/Scala 方法的最早方法是什么?
What is the earliest way to call a Java/Scala method?
我使用一些脏代码在 second answer of this question
的 Scala 中设置环境变量
我在 IDE(IDEA Intellij) 中对此进行了测试,并在 class.
的开头设置了 OMP_NUM_THREADS
import org.scalatest.{FlatSpec, Matchers}
class MyTest extends FlatSpec with Matchers {
val m = Map("OMP_NUM_THREADS" -> "1")
EnvHacker.setEnv(m)
设置后,我可以读取 System.env
,它有效。但是当我的程序运行s的时候,并没有用到这个。我试过在静态块中设置它,但仍然不起作用。
但是如果我在 IDE 运行 配置中设置它(在 JVM 运行 之前),它会像我预期的那样工作并且 运行s。所以它似乎在我修改变量之前被读取了。
或者换句话说,我有一段代码,最早在Java/Scala中调用它的方式是什么。例如在main方法的第一行之前调用静态块。
更新了一些细节:
我正在使用tensorflow-mkl Java API,它会在某个时候读取系统环境变量OMP_NUM_THREADS
,根据我的测试结果,这个操作是在系统静态之前堵塞。但是,我想在代码中控制,因为我不知道没有代码逻辑的配置。
我 认为 这可能会做你想做的事,我从另一个问题中借用了 env 黑客(非常讨厌的黑客!),我的理解是你想设置一些环境变量并在主要方法中提供它们(基本上尽可能早)。
import java.util.{Collections, Map => JavaMap}
import scala.collection.JavaConverters._
object EnvHacker {
/**
* Portable method for setting env vars on both *nix and Windows.
* @see
*/
def setEnv(newEnv: Map[String, String]): Unit = {
try {
val processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment")
val theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment")
theEnvironmentField.setAccessible(true)
val env = theEnvironmentField.get(null).asInstanceOf[JavaMap[String, String]]
env.putAll(newEnv.asJava)
val theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment")
theCaseInsensitiveEnvironmentField.setAccessible(true)
val cienv = theCaseInsensitiveEnvironmentField.get(null).asInstanceOf[JavaMap[String, String]]
cienv.putAll(newEnv.asJava)
} catch {
case e: NoSuchFieldException =>
try {
val classes = classOf[Collections].getDeclaredClasses
val env = System.getenv()
for {cl <- classes} {
if (cl.getName == "java.util.Collections$UnmodifiableMap") {
val field = cl.getDeclaredField("m")
field.setAccessible(true)
val obj = field.get(env)
val map = obj.asInstanceOf[JavaMap[String, String]]
map.clear()
map.putAll(newEnv.asJava)
}
}
} catch {
case e2: Exception => e2.printStackTrace()
}
case e1: Exception => e1.printStackTrace()
}
}
}
class Main extends {
val NumThreads = "OP_NUM_THREADS"
EnvHacker.setEnv(Map(NumThreads -> "100"))
}
object Main extends Main {
def main(args: Array[String]): Unit = {
println(System.getenv(NumThreads)) // prints 100
}
}
我认为这是一个 XY problem:您想通过“OMP_NUM_THREADS”env 控制 OpenMP,但您不能或不想为您的进程设置实际的环境变量一些理由?是吗?
您如何调用 OpenMP? OpenMP 是一个 C 库 https://www.openmp.org/ ,因此它不会注意到您对 java.lang.ProcessEnvironment#theEnvironment
字段所做的任何更改,无论您设置它的时间有多早。
如果您通过 exec
调用调用 OpenMP,那么您应该能够将新环境传递给它。
如果您通过 JNI 调用 OpenMP,那么您将无法从 Java 更改您的环境变量,您需要在启动进程时实际设置 env。参见 Can I set an Environment Variable for Java Native Interface (JNI) libraries?
您可以使用 omp_set_num_threads()
而不是 OMP_NUM_THREADS
env 吗?
我使用一些脏代码在 second answer of this question
的 Scala 中设置环境变量我在 IDE(IDEA Intellij) 中对此进行了测试,并在 class.
的开头设置了OMP_NUM_THREADS
import org.scalatest.{FlatSpec, Matchers}
class MyTest extends FlatSpec with Matchers {
val m = Map("OMP_NUM_THREADS" -> "1")
EnvHacker.setEnv(m)
设置后,我可以读取 System.env
,它有效。但是当我的程序运行s的时候,并没有用到这个。我试过在静态块中设置它,但仍然不起作用。
但是如果我在 IDE 运行 配置中设置它(在 JVM 运行 之前),它会像我预期的那样工作并且 运行s。所以它似乎在我修改变量之前被读取了。
或者换句话说,我有一段代码,最早在Java/Scala中调用它的方式是什么。例如在main方法的第一行之前调用静态块。
更新了一些细节:
我正在使用tensorflow-mkl Java API,它会在某个时候读取系统环境变量OMP_NUM_THREADS
,根据我的测试结果,这个操作是在系统静态之前堵塞。但是,我想在代码中控制,因为我不知道没有代码逻辑的配置。
我 认为 这可能会做你想做的事,我从另一个问题中借用了 env 黑客(非常讨厌的黑客!),我的理解是你想设置一些环境变量并在主要方法中提供它们(基本上尽可能早)。
import java.util.{Collections, Map => JavaMap}
import scala.collection.JavaConverters._
object EnvHacker {
/**
* Portable method for setting env vars on both *nix and Windows.
* @see
*/
def setEnv(newEnv: Map[String, String]): Unit = {
try {
val processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment")
val theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment")
theEnvironmentField.setAccessible(true)
val env = theEnvironmentField.get(null).asInstanceOf[JavaMap[String, String]]
env.putAll(newEnv.asJava)
val theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment")
theCaseInsensitiveEnvironmentField.setAccessible(true)
val cienv = theCaseInsensitiveEnvironmentField.get(null).asInstanceOf[JavaMap[String, String]]
cienv.putAll(newEnv.asJava)
} catch {
case e: NoSuchFieldException =>
try {
val classes = classOf[Collections].getDeclaredClasses
val env = System.getenv()
for {cl <- classes} {
if (cl.getName == "java.util.Collections$UnmodifiableMap") {
val field = cl.getDeclaredField("m")
field.setAccessible(true)
val obj = field.get(env)
val map = obj.asInstanceOf[JavaMap[String, String]]
map.clear()
map.putAll(newEnv.asJava)
}
}
} catch {
case e2: Exception => e2.printStackTrace()
}
case e1: Exception => e1.printStackTrace()
}
}
}
class Main extends {
val NumThreads = "OP_NUM_THREADS"
EnvHacker.setEnv(Map(NumThreads -> "100"))
}
object Main extends Main {
def main(args: Array[String]): Unit = {
println(System.getenv(NumThreads)) // prints 100
}
}
我认为这是一个 XY problem:您想通过“OMP_NUM_THREADS”env 控制 OpenMP,但您不能或不想为您的进程设置实际的环境变量一些理由?是吗?
您如何调用 OpenMP? OpenMP 是一个 C 库 https://www.openmp.org/ ,因此它不会注意到您对 java.lang.ProcessEnvironment#theEnvironment
字段所做的任何更改,无论您设置它的时间有多早。
如果您通过 exec
调用调用 OpenMP,那么您应该能够将新环境传递给它。
如果您通过 JNI 调用 OpenMP,那么您将无法从 Java 更改您的环境变量,您需要在启动进程时实际设置 env。参见 Can I set an Environment Variable for Java Native Interface (JNI) libraries?
您可以使用 omp_set_num_threads()
而不是 OMP_NUM_THREADS
env 吗?