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.
>