Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Scala中将参数传递给singleton对象_Scala_Apache Spark - Fatal编程技术网

在Scala中将参数传递给singleton对象

在Scala中将参数传递给singleton对象,scala,apache-spark,Scala,Apache Spark,我继承了一个需要扩展的Scala项目,而不是一个单一的庞然大物,它必须被拆分:一些代码需要成为一个库,供所有其他组件使用,还有一些应用程序可能会在以后的某个时候包括进来 object Shared { // vals, defs } ===== import Shared._ object Utils1 { // vals, defs } ===== import Shared._ object Utils2 { // vals, defs } ===== impor

我继承了一个需要扩展的Scala项目,而不是一个单一的庞然大物,它必须被拆分:一些代码需要成为一个库,供所有其他组件使用,还有一些应用程序可能会在以后的某个时候包括进来

object Shared {
  // vals, defs
}

=====

import Shared._

object Utils1 {
  // vals, defs
}

=====

import Shared._

object Utils2 {
  // vals, defs
}

=====

import Shared._
import Utils1._

class Class1(val ...) {
  // stuff
}

=====

import Shared._
import Utils2._

class Class2(val ...) {
  // more stuff
}

etc.
问题是
Utils1
Utils2
(以及许多其他对象和类)使用
Shared
(单例)中的值,现在必须实例化
Shared
,因为
Shared
中发生的关键事情之一是设置了应用程序名称(通过
SparkConf
)以及读取带有数据库连接信息的配置文件

其想法是建立一个多项目的构建,在这里我可以选择需要重新编译的组件并执行它。由于
Utils
中的代码几乎被当前存在和即将出现的所有应用程序共享,所以将其保存在一个大型项目中很好,至少我是这么认为的。很难将常见的代码发布到本地存储库中,因为我们还没有本地存储库,并且很难获得拥有本地存储库的许可

需要
Utils
单例,因为它们必须是静态的(因为Spark和可序列化性)

当我将
Shared
作为一个合适的类时,所有的
import
语句都将变得无用,我必须传递一个实例,这意味着我不能使用单例,即使我需要它们。它目前可以工作,因为只有一个应用程序,所以实际上只有一个
Shared
实例。将来,每个应用程序仍将只有一个共享的
实例,但单个项目中可能定义了多个应用程序/服务

我已经研究过隐式、包对象和依赖项注入,但我不确定这是一条正确的道路。也许我只是看不到什么是显而易见的


长话短说,有没有一种简洁的方法来给出
Shared
一个参数或实现我希望实现的目标

作为一个选项,您可以创建
SharedClass
类,并使
Shared
对象使用不同的构造函数参数在每个应用程序中扩展它:

  class SharedClass(val param: String) { // vals ...       
  }

  object Shared extends SharedClass("value")

作为一个选项,您可以创建
SharedClass
类,并使用不同的构造函数参数在每个应用程序中扩展
Shared
对象:

  class SharedClass(val param: String) { // vals ...       
  }

  object Shared extends SharedClass("value")

其中一种方法是使用
DynamicVariable
并在初始化
Shared
时使其具有值(即,第一次调用任何引用
Shared
字段或方法的内容)

考虑以下几点:

/* File: Config.scala */

import scala.util.DynamicVariable

object Config {
  val Cfg: DynamicVariable[String] = new DynamicVariable[String](null)
}

/**********************/

/* File: Shared.scala */

import Config._

object Shared {
  final val Str: String = Cfg.value

  def init(): Unit = { }
}

/*********************/

/* File: Utils.scala */

import Shared._

object Utils {
  def Length: Int = Str.length
}

/********************/

/* File: Main.scala */

object Main extends App 
{
  // Make sure `Shared` is initialized with the desired value
  Config.Cfg.withValue("foobar") {
    Shared.init()
  }

  // Now Shared.Str is fixed for the duration of the program
  println(Shared.Str)     // prints: foobar
  println(Utils.Length)   // prints: 6
}
当然,这种设置是线程安全的,尽管不是确定性的。以下
Main
将随机选择3个字符串中的一个,并将所选字符串及其长度打印3次:

import scala.util.Random
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

object Main extends App
{
  def random(): Int = Random.nextInt(100)

  def foo(param: String, delay: Int = random()): Future[Unit] = {
    Future {
      Thread.sleep(delay)

      Config.Cfg.withValue(param) {
        Shared.init()
      }

      println(Shared.Str)
      println(Utils.Length)
    }
  }

  foo("foo")
  foo("foobar")
  foo("foobarbaz")

  Thread.sleep(1000)

}

其中一种方法是使用
DynamicVariable
并在初始化
Shared
时使其具有值(即,第一次调用任何引用
Shared
字段或方法的内容)

考虑以下几点:

/* File: Config.scala */

import scala.util.DynamicVariable

object Config {
  val Cfg: DynamicVariable[String] = new DynamicVariable[String](null)
}

/**********************/

/* File: Shared.scala */

import Config._

object Shared {
  final val Str: String = Cfg.value

  def init(): Unit = { }
}

/*********************/

/* File: Utils.scala */

import Shared._

object Utils {
  def Length: Int = Str.length
}

/********************/

/* File: Main.scala */

object Main extends App 
{
  // Make sure `Shared` is initialized with the desired value
  Config.Cfg.withValue("foobar") {
    Shared.init()
  }

  // Now Shared.Str is fixed for the duration of the program
  println(Shared.Str)     // prints: foobar
  println(Utils.Length)   // prints: 6
}
当然,这种设置是线程安全的,尽管不是确定性的。以下
Main
将随机选择3个字符串中的一个,并将所选字符串及其长度打印3次:

import scala.util.Random
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

object Main extends App
{
  def random(): Int = Random.nextInt(100)

  def foo(param: String, delay: Int = random()): Future[Unit] = {
    Future {
      Thread.sleep(delay)

      Config.Cfg.withValue(param) {
        Shared.init()
      }

      println(Shared.Str)
      println(Utils.Length)
    }
  }

  foo("foo")
  foo("foobar")
  foo("foobarbaz")

  Thread.sleep(1000)

}
Scala中的对象具有可用于此目的的“应用”方法。因此,您的共享对象如下所示

object Shared {
  def apply(param1: String, param2: String) = ???
}
现在,Shared的每个客户端都可以传递不同的值。

Scala中的对象具有“应用”方法,您可以使用该方法来实现此目的。因此,您的共享对象如下所示

object Shared {
  def apply(param1: String, param2: String) = ???
}

现在,Shared的每个客户端都可以传递不同的值。

否,您不能向Shared添加参数。在需要时将参数传递给
Shared
的方法如何?否,您无法向Shared添加参数在需要时如何将参数传递给
Shared
的方法?如何在不同的对象/类中使用
Shared
<代码>共享
将仅在每个应用程序的
main
中设置,并且
取决于应用程序。
Utils
中的实用程序函数仍然需要获得一个实例,这些实例本身就是单例。我的意思是,你可以在每个应用程序中分别定义这个对象。它仍然是
singleton
。我如何在不同的对象/类中使用
Shared
<代码>共享将仅在每个应用程序的
main
中设置,并且
取决于应用程序。
Utils
中的实用程序函数仍然需要获得一个实例,这些实例本身就是单例。我的意思是,你可以在每个应用程序中分别定义这个对象。它仍然是
singleton
。是不是只有我才散发出全局变量的味道?你会建议我把怪物重构成不同的类实例,并从依赖于这些“环境”变量的对象中取出东西吗?@Ian,是的。(从技术上讲,它更像全局常量:值只设置一次)。但是使用
Shared
singleton已经有点像使用全局状态了。这个答案只是为了说明它在技术上是如何可能的,我从来没有在生产中使用过这样的东西。(另一种方法是简单地从环境变量或配置文件加载值)一些重构可能是有序的,或者您可以尝试使用依赖项注入框架。我没有使用过Spark,所以我不确定哪种解决方案有效,哪种更好。是不是只有我一个人,但那充满了全局变量的味道?你会建议我把怪物重构成不同的类实例,并从依赖于这些“环境”变量的对象中取出东西吗?@Ian,是的。(从技术上讲,它更像全局常量:值只设置一次)。但是使用
Shared
singleton已经有点像使用全局状态了。这个答案只是为了让她相信