My wording above is not entirely accurate, since you yourself can't set 
`#6#v` as a variable. It's a product of how local variable names are parsed 
when macros are expanded:

julia> macro foo()
           quote 
               v = 5 
               return v 
           end 
       end 

julia> macroexpand(:( @foo )) 
quote  # none, line 3: 
    #15#v = 5 # line 4: 
    return #15#v 
end


This prevents variables declared within the body of a macro definition from 
interacting with identically named variables declared outside the 
definition. Here is the definition of `@sync`, which is very similar to the 
toy example above: 
https://github.com/JuliaLang/julia/blob/e97588db65f590d473e7fbbb127f30c01ea94995/base/task.jl#L340
 

`gensym()` serves a similar purpose when one is building expressions within 
the body of a regular function:

julia> v = gensym("v")
symbol("##v#8970") 

julia> v 
symbol("##v#8970")


See: http://docs.julialang.org/en/latest/manual/metaprogramming/#hygiene


On Wednesday, June 17, 2015 at 8:44:53 AM UTC-4, Daniel Carrera wrote:
>
> Wait.... #6#v is the name of a variable? How is that possible?
>
> On 17 June 2015 at 14:25, David Gold <[email protected] <javascript:>> 
> wrote:
>
>> Actually, it seems that @sync is also responsible for setting the 
>> variable #6#v equal to the return object of the call to Base.pfor and then 
>> returning #6#v after calling Base.sync_end().
>>
>> On Wednesday, June 17, 2015 at 8:22:08 AM UTC-4, David Gold wrote:
>>>
>>> Have you tried macroexpanding the expression? Doing so yields
>>>
>>> julia> macroexpand(:( for i = 1:N 
>>>                           @sync @parallel for j = (i + 1):N  
>>>                               tmp[j] = i * j  
>>>                           end 
>>>                       end )) 
>>>
>>> :(for i = 1:N # line 2: 
>>>         begin  # task.jl, line 342: 
>>>             Base.sync_begin() # line 343: 
>>>             #6#v = begin  # multi.jl, line 1487: 
>>>                     Base.pfor($(Expr(:localize, :(()->begin  # expr.jl, 
>>> line 113: 
>>>             begin  # multi.jl, line 1460: 
>>>                 function (#7#lo::Base.Int,#8#hi::Base.Int) # multi.jl, 
>>> line 1461: 
>>>                     for j = (i + 1:N)[#7#lo:#8#hi] # line 1462: 
>>>                         begin  # line 3: 
>>>                             tmp[j] = i * j 
>>>                         end 
>>>                     end 
>>>                 end 
>>>             end 
>>>         end))),Base.length(i + 1:N)) 
>>>                 end # line 344: 
>>>             Base.sync_end() # line 345: 
>>>             #6#v 
>>>         end 
>>>     end)
>>>
>>>
>>>  It looks like @parallel does the work of setting up a properly 
>>> formatted call to Base.pfor. In particular, it builds an Expr object with 
>>> head :localize and argument a zero-arg anonymous function, and then passes 
>>> the interpolation of that expression along with `Base.length(i + 1:N)` to 
>>> Base.pfor. The body of the anonymous function declares another function 
>>> with arguments `#7#lo`, `#8#hi`. The latter variables somehow annotate the 
>>> delimiters of your inner loop, which gets reproduced inside the body of the 
>>> declared function. I'm *guessing* that the anonymous function is used as a 
>>> vehicle to pass the code of the annotated inner loop to Base.pfor without 
>>> executing it beforehand. But I could be wrong.
>>>
>>>
>>> Then @sync just wraps all the above between calls to `Base.sync_begin` 
>>> and `Base.sync_end`.
>>>
>>>
>>> I also should note I have zero experience with Julia's parallel 
>>> machinery and am entirely unfamiliar with the internals of Base.pfor. I 
>>> just enjoy trying to figure out macros.
>>>
>>> On Wednesday, June 17, 2015 at 5:49:58 AM UTC-4, Daniel Carrera wrote:
>>>>
>>>>
>>>> On Wednesday, 17 June 2015 10:28:37 UTC+2, Nils Gudat wrote:
>>>>>
>>>>> I haven't used @everywhere in combination with begin..end blocks, I 
>>>>> usually pair @sync with @parallel - see an example here 
>>>>> <https://github.com/nilshg/LearningModels/blob/master/NHL/NHL_6_Bellman.jl>,
>>>>>  
>>>>> where I've parallelized the entire nested loop ranging from lines 25 to 
>>>>> 47. 
>>>>>
>>>>
>>>>
>>>> Aha! Thanks. Copying your example I was able to produce this:
>>>>
>>>>     N = 5
>>>>     tmp = SharedArray(Int, (N))
>>>>     
>>>>     for i = 1:N
>>>>         # Compute tmp in parallel #
>>>>         @sync @parallel for j = (i + 1):N
>>>>             tmp[j] = i * j
>>>>         end
>>>>         
>>>>         # Consume tmp in serial #
>>>>         for j = (i + 1):N
>>>>             println(tmp[j])
>>>>         end
>>>>     end
>>>>
>>>>
>>>> This seems to work correctly and gives the same answer as the serial 
>>>> code. Can you help me understand how it works? What does "@sync @parallel" 
>>>> do? I feel like I half-understand it, but the concept is not clear in my 
>>>> head.
>>>>
>>>> Thanks.
>>>>
>>>> Daniel.
>>>>
>>>
>
>
> -- 
> When an engineer says that something can't be done, it's a code phrase 
> that means it's not fun to do.
>  

Reply via email to