调用 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 吗?