【问题标题】:What is the earliest way to call a Java/Scala method?调用 Java/Scala 方法的最早方法是什么?
【发布时间】:2021-05-17 03:02:52
【问题描述】:

我使用一些脏代码在 Scala 中从 second answer of this question 设置环境变量

我在 IDE(IDEA Intellij) 中对此进行了测试,并在课程开始时设置了 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 读取,它可以工作。但是当我的程序运行时,它不使用它。我尝试将它设置在静态块中,但仍然无法正常工作。

但如果我在 IDE 运行配置中设置它(在 JVM 运行之前),它会按我的预期工作和运行。所以似乎是在我修改变量之前读取的。

或者换句话说,我有一段代码,在 Java/Scala 中调用它的最早方式是什么。例如在 main 方法的第一行之前调用 static 块。

更新了一些细节:

我使用的是tensorflow-mkl Java API,它有时会读取系统环境变量OMP_NUM_THREADS,根据我的测试结果,这个操作是在系统静态块之前。但是,我想在代码中进行控制,因为我不知道没有代码逻辑的预期配置。

【问题讨论】:

  • 您的程序如何检索此环境变量?会不会是它在您运行 EnvHacker.setEnv 之前检索它?
  • @GaëlJ 我想是的,那么它在运行代码的第一行之前检索到任何条件吗?
  • 这完全取决于您的程序在何处/何时检索此环境变量。如果这是您使用的框架/库的一部分,要么他们提供了某种“挂钩”,您可以在他们的代码运行之前调用它们,或者这可能是一个死胡同。
  • 澄清一下,您是否只在某些测试或应用运行时才需要此环境变量?
  • 在运行时,我想对进程做更多的控制,但此时不想创建其他进程。如果没有办法,也许我会创建另一个使用 ProcessBuilder

标签: java scala environment-variables


【解决方案1】:

我认为这是XY problem:您想通过“OMP_NUM_THREADS”环境控制 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 吗?

【讨论】:

  • 没错!这是一个 XY 问题。我添加了一些问题的细节。您说“您将无法从 Java 更改环境变量”,但黑客代码似乎有效。原来 tensorflow-mkl java api 没有从 JNI 调用 OpenMP?我说对了吗?
  • 我不知道 tensorflow-mkl java 如何调用 OpenMP,我在 5 分钟的谷歌搜索中无法弄清楚。我认为你真正的问题更像是“我如何控制 OpenMP 在 tensorflow-mkl java 中使用的线程数”,但我对那个工具链不是很熟悉。我认为在理想情况下,您会关闭此问题并使用该标题和设置的一些详细信息打开一个新问题,但是如果您有适合您的解决方案,那么也许不需要。这个问题对任何其他 Java 开发人员都没有用,因为它有一个误导性的 IMO 标题。 GL!
【解决方案2】:

认为这可能会做你想做的事,我从另一个问题中借用了 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 http://stackoverflow.com/a/7201825/293064
     */
    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
  }
}

【讨论】:

  • 我认为这条评论与问题关系不大
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-25
  • 1970-01-01
  • 2012-03-16
  • 1970-01-01
  • 2012-05-15
相关资源
最近更新 更多