-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adds interpolation syntax to Threads.@spawn
, to evaluate arguments immediately
#33119
Conversation
(If we move forward with this PR, we'll probably want to add an equivalent for |
I am not the biggest fan of adding a new name/verb with subtlety different behavior. I liked Jeff's idea of passing arguments to be evaluated, which seems similar to |
Yeah, i agree, i think that's a reasonable concern. Thanks.
My concerns with passing arguments to be evaluated are two-fold:
But yeah, i do agree that it could be non-ideal to have these two verbs that are pretty similar yet subtly different... What if this also had a different syntax, not just a different name? That could help distinguish them better? function spawnfunc(f)
(args...; kwargs...) -> @spawn f(args...; kwargs...)
end julia> spawnfunc(println)(1)
1
Task (done) @0x0000000114d958d0
julia> fetch(spawnfunc(sort)([3 2; 1 0], dims=2))
2×2 Array{Int64,2}:
2 3
0 1 EDIT: One problem with doing it this way, I think, is that enclosing |
... Or, as another idea, maybe we should just use So it'd be something like |
I love the interpolation idea. |
It's growing on me as well. Oh, haha, i just realized i already suggested it back in January as well, in the original issue... haha it's funny how our brains are little automata that respond the same way to the same situations... 😅😬 Here's what I said then:
I'm less worried about that caveat now than I was then.. I think all the cases where this would start to take affect would currently be While i'm here, i'll copy over the other references from the original issue:
|
IIUC the semantics of Cilk and Go agree here, they both use The general closure syntax of |
Since there haven't been any further comments on this PR, i've gone ahead and implemented the It seems pretty good to me! And i am 95% sure it is a non-breaking change, since it's only weakening the pre-conditions on valid input. :) The original example now works, via this interpolation: begin
outs = zeros(5)
@sync begin
local i = 1
while i <= 5
Threads.@spawn setindex!(outs, $i, $i)
i += 1
end
end
@test outs == 1:5
end If we're happy with this, we can move the implementation to a shared common location, and use it in |
I guess one very real problem with the current approach is that the julia> @eval $(Expr(:call, :+, x, x))
4
julia> fetch(@spawn $(Expr(:call, :+, x, x)))
:(2 + 2)
julia> @btime $(Expr(:call, :+, x, x))
0.036 ns (0 allocations: 0 bytes)
4 I'm afraid this might be confusing. EDIT: Though maybe not... See below: That said, after thinking about it more, I guess actually the behavior is consistent with the meaning of julia> "$(Expr(:call, :+, x, x))"
"2 + 2"
julia> :($(Expr(:call, :+, x, x)))
:(2 + 2) So maybe there's nothing wrong here after-all? It does seem a bit mysterious though, because people might be used to interpolating into an |
Threads.@spawncall
, which evaluates arguments immediatelyThreads.@spawn
, to evaluate arguments immediately
Bump, this seems like a really nice idea. cc @JeffBezanson, @vtjnash |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me! Just a bit of polish and adding news and I think this is good to go.
base/threadingconstructs.jl
Outdated
@@ -103,22 +103,28 @@ Create and run a [`Task`](@ref) on any available thread. To wait for the task to | |||
finish, call [`wait`](@ref) on the result of this macro, or call [`fetch`](@ref) | |||
to wait and then obtain its return value. | |||
|
|||
(Values can be interpolated into `@spawn` via `\$` to evaluate them in the current task.) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be a !!! compat
note
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, thanks. Is it okay that I added the compat note below like this, or should it go above the section on $
-interpolation? Should I move that paragraph below the compat notes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the review, @vchuravy, and sorry for the delay! :)
EDIT: also added NEWS. (Unclear why the macos test is failing, but seems unrelated?)
base/threadingconstructs.jl
Outdated
@@ -103,22 +103,28 @@ Create and run a [`Task`](@ref) on any available thread. To wait for the task to | |||
finish, call [`wait`](@ref) on the result of this macro, or call [`fetch`](@ref) | |||
to wait and then obtain its return value. | |||
|
|||
(Values can be interpolated into `@spawn` via `\$` to evaluate them in the current task.) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, thanks. Is it okay that I added the compat note below like this, or should it go above the section on $
-interpolation? Should I move that paragraph below the compat notes?
Friendly ping. I think this was mostly ready to go? :) |
Can you squash and rebase? |
Yes, let's get this rebased and merged. |
This acts more like a "parallel function call", where the arguments are evaluated immediately, in the current thread, and the function is then invoked in any available thread with the stored argument values. This prevents variables being "boxed" in order to capture them in the closure.
This acts more like a "parallel function call", where the arguments are evaluated immediately, in the current thread, and the function is then invoked in any available thread with the stored argument values. This prevents variables being "boxed" in order to capture them in the closure. Fix at-spawncall to work w/ kwargs; add unit tests Rough implementation of `$`-interpolation in at-spawn
This acts more like a "parallel function call", where the arguments are evaluated immediately, in the current thread, and the function is then invoked in any available thread with the stored argument values. This prevents variables being "boxed" in order to capture them in the closure. Fix at-spawncall to work w/ kwargs; add unit tests Rough implementation of `$`-interpolation in at-spawn Update spawncall tests to exercise the interpolation Fix my basic "lift $" function for $ inside :() Add string-interp test Escape the `$` reference in at-spawn docstring Oops, remove spurious "end" at end of file Factor out `$`-lifting; share b/w `@async` & `@spawn`
I'm on vacation in Kerala, India (it's gorgeous here!! 😁)
But the internet is pretty crappy AND I only brought my crappy Chromebook.
I just rebased and pushed. It's building locally now, but it takes about 20
min to download and build 😅, and we just had to leave to go shopping. I'll
check again when I'm back.
Thanks for looking at this! Hope it can make it into 1.4
…On Tue, Dec 17, 2019 at 1:22 AM Jeff Bezanson ***@***.***> wrote:
Yes, let's get this rebased and merged.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#33119?email_source=notifications&email_token=AAMCIEPMRW3TWY4P6Q3ZE2DQY7L6BA5CNFSM4ISJBH42YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEG74JTQ#issuecomment-566215886>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAMCIEL2XMEEIFVMUXXFK7LQY7L6BANCNFSM4ISJBH4Q>
.
|
…uate arguments immediately. Add the ability to evaluate some parts of a `@spawn`/`@async` immediately, in the current thread context. This prevents variables being "boxed" in order to capture them in the closure, exactly the same as wrapping them in a let-block locally. For example, `$x` expands like this: ```julia julia> @macroexpand @async $x + 2 quote #= task.jl:361 =# let var"#JuliaLang#454" = x #= task.jl:362 =# local var"JuliaLang#9#task" = Base.Task((()->begin #= task.jl:358 =# var"#JuliaLang#454" + 2 end)) #= task.jl:363 =# if $(Expr(:islocal, Symbol("##sync#95"))) #= task.jl:364 =# Base.push!(var"##sync#95", var"JuliaLang#9#task") end #= task.jl:366 =# Base.schedule(var"JuliaLang#9#task") #= task.jl:367 =# var"JuliaLang#9#task" end end ```
Okay looks good! :) It looks like the windows test failure is a flake? Thanks for the review |
Introduce synchronization (via a `Channel()`) to force spawned tasks to run after the local variables are updated, showcasing the problem and the solution with `$`-interpolation.
Introduce synchronization (via a `Channel()`) to force spawned tasks to run after the local variables are updated, showcasing the problem and the solution with `$`-interpolation.
Introduce synchronization (via a `Channel()`) to force spawned tasks to run after the local variables are updated, showcasing the problem and the solution with `$`-interpolation.
…immediately (#33119) Adds $-interpolation syntax to `@async` and `Threads.@spawn`, to evaluate arguments immediately. Add the ability to evaluate some parts of a `@spawn`/`@async` immediately, in the current thread context. This prevents variables being "boxed" in order to capture them in the closure, exactly the same as wrapping them in a let-block locally. For example, `$x` expands like this: ```julia julia> @macroexpand @async $x + 2 quote #= task.jl:361 =# let var"##454" = x #= task.jl:362 =# local var"#9#task" = Base.Task((()->begin #= task.jl:358 =# var"##454" + 2 end)) #= task.jl:363 =# if $(Expr(:islocal, Symbol("##sync#95"))) #= task.jl:364 =# Base.push!(var"##sync#95", var"#9#task") end #= task.jl:366 =# Base.schedule(var"#9#task") #= task.jl:367 =# var"#9#task" end end ```
Introduce synchronization (via a `Channel()`) to force spawned tasks to run after the local variables are updated, showcasing the problem and the solution with `$`-interpolation.
I wonder if this could be made more general? Perhaps marking any closure with |
As a bonus, |
Adds $-interpolation syntax to
@async
andThreads.@spawn
, to evaluate arguments immediately.Add the ability to evaluate some parts of a
@spawn
/@async
immediately, in the current thread context.
This prevents variables being "boxed" in order to capture them in the
closure, exactly the same as wrapping them in a let-block locally.
For example,
$x
expands like this:Fixes #30896
Add the ability to evaluate some parts of a
@spawn
immediately, in the current thread context.Adds a new macro,Threads.@spawncall
, which evaluates its arguments immediately, then@spawn
s the closure with the argument values.This acts more like a "parallel function call", where the arguments are evaluated immediately, in the current thread, and the function is then invoked in any available thread with the stored argument values.EDIT: Updated to add
$
-interpolation syntax support to@spawn
to allow you to manually specify which parts of the expression to evaluate early.This prevents variables being "boxed" when capturing them in the closure.
This mirrors the behavior of golangsgo
command, which requires it be used with a function call.Fixes #30896