在 Spark 中实现单例模式的技巧

单例模式是一种常用的设计模式,但是在集群模式下的 Spark 中使用单例模式会引发一些错误。我们用下面代码作例子,解读在 Spark 中使用单例模式遇到的问题。

object Example{
  var instance:Example = new Example("default_name");
  def getInstance():Example = {
    return instance
  }
  def init(name:String){
    instance = new Example(name)
  }
}
class Example private(name1:String) extends  Serializable{
  var name = name1
}

object Main{
  def main(args:Array[String]) = {
    Example.init("To create happiness with money")
    val sc =  new SparkContext(new SparkConf().setAppName("test"))

    val rdd = sc.parallelize(1 to 10, 3)
    rdd.map(x=>{
      x + "_"+ Example.getInstance().name
    }).collect.foreach(println)
  }
}

我们预期结果是数字和腾讯游戏座右铭,然后实际的结果确实数字和默认名字,如下所示

就像 Example.init(“To create happiness with money”) 没有执行一样。在 Stackoverflow 上,有不少人也碰到这个错误,比如 问题1问题2问题3

这是由什么原因导致的呢?Spark 执行算子之前,会将算子需要东西准备好并打包(这就是闭包的概念),分发到不同的 executor,但这里不包括类。类存在 jar 包中,随着 jar 包分发到不同的 executors 中。当不同的 executors 执行算子需要类时,直接从分发的 jar 包取得。这时候在 driver 上对类的静态变量进行改变,并不能影响 executors 中的类。拿上面的程序做例子,jar 包存的 Example.instance = new Example(“default_name”),分发到不同的 executors。这时候不同 executors 中 Example.getInstance().name 等于 “default_name”。

这个部分涉及到 Spark 底层原理,很难堂堂正正地解决,只能采取取巧的办法。不能再 executors 使用类,那么我们可以用对象嘛。我们可以把 Example 的实例对象塞进算子的闭包,随着闭包分发到不同的 executors。修改之后的代码如下所示。

object Main{
  def main(args:Array[String]) = {
    Example.init(""To create happiness with money"")
    val sc =  new SparkContext(new SparkConf().setAppName("test"))
    
    val instance = Example.getInstance()
    val rdd = sc.parallelize(1 to 10, 3)
    rdd.map(x=>{
      x + "_"+ instance.name
    }).collect.foreach(println)
  }
}

上面代码在集群模式下的 Spark 运行结果是数字和腾讯游戏座右铭。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏owent

打造最快的Hash表(转) [以暴雪的游戏的Hash为例]

先提一个简单的问题,如果有一个庞大的字符串数组,然后给你一个单独的字符串,让你从这个数组中查找是否有这个字符串并找到它,你会怎么做?

703
来自专栏为数不多的Android技巧

Java高效分割字符串

最近优化一段代码的调用时间,发现性能瓶颈居然是io和split!io操作慢情有可原,那么对于split有没有更高效的方法呢?

862
来自专栏后端之路

枚举高性能之EnumMap

背景 想必使用Java5之后枚举已经是每一个Java开发者很常用的工具了。特别是用来实现单例模式通过枚举也是一种推荐的方式。 大部分开发者也有根据枚举回去Map...

26210
来自专栏搜云库

BTA 常问的 Java基础40道常见面试题及详细答案

最近看到网上流传着,各种面试经验及面试题,往往都是一大堆技术题目贴上去,而没有答案。

4966
来自专栏老马说编程

(50) 剖析EnumMap / 计算机程序的思维逻辑

查看历史文章,请点击上方链接关注公众号。 上节我们提到,如果需要一个Map的实现类,并且键的类型为枚举类型,可以使用HashMap,但应该使用一个专门的实现类E...

1788
来自专栏Java帮帮-微信公众号-技术文章全总结

Java代码效率优化【面试+提高】

JAVA代码效率优化 最近在想自己编程时是否注意过代码的效率问题,得出的答案是:没有。代码只是实现了功能,至于效率高不高没怎么关注,这应该是JAVA程序员进阶...

38413
来自专栏Spark生态圈

[Spark SQL] 主要执行流程

SparkSql的第一件事就是把SQLText解析成语法树,这棵树包含了很多节点对象,节点可以有特定的数据类型,同时可以有0个或者多个子节点,节点在SparkS...

601
来自专栏orientlu

FreeRTOS 内存 Heap管理

FreeRtos 提供的几种 heap 管理在源码目录 Source/Portable/MemMang 下,选择哪种类型管理直接在编译时把原文件加入(比如在 m...

663
来自专栏刘望舒

设计模式(九)模版方法模式

1.模版方法模式简介 模版方法模式介绍 在软件开发中,有时会遇到类似的情况,某个方法的实现需要多个步骤,其中有些步骤是固定的,而有些步骤并不固定,存在可变性。为...

1836
来自专栏玩转JavaEE

Redis列表与集合

前面文章我们介绍了STRING的基本命令,本文我们来看看Redis中的列表与集合。 本文是Redis系列的第五篇文章,了解前面的文章有助于更好的理解本文: --...

2737

扫码关注云+社区