Spark學習第二天之---共享變量Broadcast Variable(廣播變量)和Accumulator(共享變量)

共享變量分爲兩種:Broadcast Variable(廣播變量) 和  Accumulator(累加變量)

什麼是共享變量

默認情況下,如果在一個算子的函數中使用到了某個外部的變量,那麼這個變量的值會被拷貝到每個task中。此時每個task只能操作自己的那份變量副本。如果多個task想要共享某個變量,那麼這種方式是做不到的。
Braadcast Variable會將使用到的變量,僅僅爲每個節點拷貝一份,更大的用處是優化性能,減少網絡傳輸以及內存消耗。
Accumulator則可以讓多個task共同操作一份變量,主要是進行累加操作。

Broadcast Variable(廣播變量的創建)

spark提供的broadcast Variable,是隻讀的。並且在每個節點上只會有一份副本,而不會爲每個task都拷貝一份副本。因此其最大作用,就是減少變量到各個節點的網絡傳輸消耗,以及在各個節點上的內存消耗。此外,spark自己內部也使用了高效的廣播算法來減少網絡消耗。

可以通過調用SparkContext的broadcast()方法,來針對某個變量創建廣播變量。然後在算子的函數中,使用到該變量的時候,每個節點只會拷貝一份副本。每個節點可以使用廣播變量的value()方法獲取值。 切記,廣播變量是只讀的。

val factor = 3
val factorBroadcast = sc.broadcast(factor)

val arr = Array(1, 2, 3, 4, 5)
val rdd = sc.parallelize(arr)
val multipleRdd = rdd.map(num => num * factorBroadcast.value())

multipleRdd.foreach(num => println(num))
package spark.stady.two;


import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.Function;
import org.apache.spark.api.java.function.VoidFunction;
import org.apache.spark.broadcast.Broadcast;


import java.util.Arrays;
import java.util.List;

/**
 * ClassName BroadcastVariable
 * Description 廣播變量
 * @author Vincent
 * @version 1.0
 * @data 2019/1/22 14:56
 */
public class BroadcastVariable {
    public static void main(String[] args) {
        //1.創建sparkConf
        SparkConf conf = new SparkConf()
                .setAppName("BroadcastVariable")
                .setMaster("local");

        //2.創建JavaSparkContext來接收conf。
        JavaSparkContext sc = new JavaSparkContext(conf);
        //3.定義一個Broadcast Variable。
        final int factor = 3;
        //創建廣播變量。
        final Broadcast<Integer> factorBroadcast = sc.broadcast(factor);
        //4.定義一個list作爲我們的RDD。
        List<Integer> numberList = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
        //5.調用我們的sparkcontext的parallelize方法將爲我們的list創建並行的RDD。
        JavaRDD<Integer> numbers = sc.parallelize(numberList);
        //6、讓RDD中的每一個數字,都進行一個 乘以外部的factor操作!
        //注意這裏面的我們沒有使用到barocast Variable。
        JavaRDD<Integer> multipleNumber = numbers.map(new Function<Integer, Integer>() {
            @Override
            public Integer call(Integer v1) throws Exception {
                return v1 * factor;
            }
        });
        multipleNumber.foreach(new VoidFunction<Integer>() {
            @Override
            public void call(Integer value) throws Exception {
                System.out.println(value);
            }
        });

        //這是我們要使用broadcast variable 的方式創建廣播變量。
        // 在第三步通過調用sc的broadcast方法來創建廣播變量。
        JavaRDD<Integer> broadcastMultipleNumber = numbers.map(new Function<Integer, Integer>() {
            @Override
            public Integer call(Integer v1) throws Exception {
                //使用共享變量,調用其value()方法,即可獲取其內部封裝的值。
                int factor = factorBroadcast.value();
                return factor * v1;
            }
        });
        broadcastMultipleNumber.foreach(new VoidFunction<Integer>() {
            @Override
            public void call(Integer value) throws Exception {
                System.out.println("broadcast variable :" + value);
            }
        });


        sc.close();
    }
}

 

上面是一個JAVA版本的案例。

Spark的還有一個Accumulator 變量:主要用於多個節點對一個變量進行共享性的操作。Accumulater只提供了累加的功能。但是卻給我們提供了多個task對一個變量並行操作的功能。但是task只能對Accumulator進行累加操作,不能讀取它的值。只有Driver程序可以讀取Accumulator的值。

package spark.stady.two;

import org.apache.spark.Accumulator;
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.VoidFunction;

import java.util.Arrays;
import java.util.List;

/**
 * ClassName Accumulator
 * Description 累加變量
 * @author Vincent
 * @version 1.0
 * @data 2019/1/23 15:10
 */
public class AccumulatorVariable {
    public static void main(String[] args) {
        SparkConf conf = new SparkConf()
                .setAppName("AccumulatorVariable")
                .setMaster("local");

        JavaSparkContext sc = new JavaSparkContext(conf);

        //創建Accumulator變量
        //需要調用sparkcontext的accumulator()方法
        final Accumulator<Integer> accumulatorsum = sc.accumulator(0);
        List<Integer> numberList = Arrays.asList(1, 2, 3, 4, 5, 6);
        JavaRDD<Integer> numbers = sc.parallelize(numberList);

        numbers.foreach(new VoidFunction<Integer>() {
            @Override
            public void call(Integer value) throws Exception {
                //然後在函數內部,就可以使用accumulator變量,調用add()方法,累加求和
                accumulatorsum.add(value);
            }
        });

        //在driver程序中,可以調用accumulator的value()方法,獲取其值
        System.out.println(accumulatorsum.value());
        sc.close();
    }
}

這是我們使用SparkContext的accumulator()方法,來實現的一個共享變量的操作,其中調用了Accumulator的add()方法進行累加,調用了Accumulator的value()方法獲取值,但是在獲取值的時候我們是在driver中獲取的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章