Github user srowen commented on a diff in the pull request:

    https://github.com/apache/spark/pull/4696#discussion_r25598156
  
    --- Diff: docs/programming-guide.md ---
    @@ -728,6 +728,69 @@ def doStuff(self, rdd):
     
     </div>
     
    +### Understanding closures <a name="ClosuresLink"></a>
    +One of the harder things about Spark is understanding the scope and life 
cycle of variables and methods when executing code across a cluster. RDD 
operations that modify variables outside of their scope can be a frequent 
source of confusion. In the example below we'll look at code that uses 
`foreach()` to increment a counter, but similar issues can occur for other 
operations as well.
    +
    +#### Example
    +
    +Consider the naive RDD element sum below, which behaves completely 
differently when running spark in `local` mode (e.g. via the shell) and when 
deploying a Spark application to a cluster (e.g. via spark-submit to YARN): 
    +
    +<div class="codetabs">
    +
    +<div data-lang="scala"  markdown="1">
    +{% highlight scala %}
    +var counter = 0
    +var rdd = sc.parallelize(data)
    +
    +// Wrong: Don't do this!!
    +rdd.foreach(x => counter += x)
    +
    +println("Counter value: " + counter)
    +{% endhighlight %}
    +</div>
    +
    +<div data-lang="java"  markdown="1">
    +{% highlight java %}
    +int counter = 0;
    +JavaRDD<Integer> rdd = sc.parallelize(data); 
    +
    +// Wrong: Don't do this!!
    +rdd.foreach(x -> counter += x;)
    +
    +println("Counter value: " + counter)
    +{% endhighlight %}
    +</div>
    +
    +<div data-lang="python"  markdown="1">
    +{% highlight python %}
    +counter = 0
    +rdd = sc.parallelize(data)
    +
    +# Wrong: Don't do this!!
    +rdd.foreach(lambda x => counter+= x)
    +
    +print("Counter value: " + counter)
    +
    +{% endhighlight %}
    +</div>
    +
    +</div>
    +
    +#### Local vs. cluster modes
    +
    +In local mode, the above code will correctly sum the values within the RDD 
and store it in **counter**. This is because both the RDD and the variable 
**counter** are in the same memory on the driver node. 
    +
    +However, in `cluster` mode, what happens is more complicated, and the 
above code will not work correctly. To execute jobs Spark breaks up the 
processing of RDD operations into tasks - each of which is operated on by an 
executor. Prior to execution, Spark computes the **closure**. The closure is 
those variables and methods which must be visible for the executor to perform 
its computations on the RDD (in this case `foreach()`). This closure is 
serialized and sent to each executor. In `local` mode, there is only the one 
executors so everything shares the same closure. In `remote` mode however, this 
is not the case and the executors running on seperate worker nodes each have 
their own copy of the closure.
    --- End diff --
    
    I'm wary of calling the first result "correct" and calling this result "not 
correct". I think the result of both is not well defined. You say this below. I 
might start by suggesting that you will probably notice a behavior difference, 
but then jump straight to that last para here that says the behavior isn't 
guaranteed.
    
    Likewise I'm a little wary of calling this a "problem" in the next para, as 
it's working as it's supposed to.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at [email protected] or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to