-
Notifications
You must be signed in to change notification settings - Fork 66
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
GIL functions for genuine multi-threading #535
Conversation
@MilesCranmer @ericphanson thought you'd like this PR - I think it's cool |
This is awesome!! |
Yeah I think this would be very very useful for the PySR/SymbolicRegression.jl ecosystem. The most requested feature is being able to use Python functionality from within user-defined custom loss functions (which ought to be run in parallel to get the best speeds). I think this feature would help enable that. Also this would make MilesCranmer/PySR#589 much less hackier |
Ok I'm happy with this except the names
|
I strongly prefer Even though I use Python for 50% of my work, I have literally never seen In Julia, Though these functions control the Python API, the exposed API is called via PythonCall.jl. Thus, I think they should respect the Julia standards. Perhaps a |
Edit: Yeah, thinking about this more, it's much more sensible to have a separate Python process for each Julia process, rather than needing all that increased complexity. |
Still though, it might be nice to have a Julian version, so you could really use the standard patterns (including other tools that just overloads using PythonCall: PythonGIL
lock(PythonGIL) do
#= do stuff =#
end Rather than needing a new Then you get stuff like (Probably should also add a |
Argh, but then again, I guess the GIL is kind of different than a normal Julia lock... So that might motivate having different names for these. I really don't know. |
Yeah I think I agree that It's a nice idea to try overloading Base functions for locking, but it's not immediately obvious how, so I'll leave that for a separate PR. |
The tricky thing here is that it would require a slightly different syntax. The (Not sure the right name here... |
Adds
PythonCall.GIL
module with:lock(f)
to executef()
with the GIL held@lock expr
the macro equivalentrelease(f)
to executef()
with the GIL released@release expr
the macro equivalentHere's an example from the tests. It calls Python's
time.sleep(1)
twice in two Julia threads.GIL.@release
is required to release the GIL so that within the threadsGIL.@lock
can re-acquire it. Sincetime.sleep
itself then releases the GIL again, the sleep actually happens in parallel and the whole block takes 1 second.Here's a similar example from the Python tests. It defines a Julia function
jsleep
which behaves pretty much liketime.sleep
. In particular it also releases the GIL, so when you calljsleep(1)
twice in parallel, it only takes 1 second in total.When using this from the Python side, if the Julia code can yield (e.g.
sleep(1)
), the threaded tasks won't finish unless you explicitly yield back from Python to let the yielding code finish. You'll probably need to yield in a loop. We could provide some functionality for this in JuliaCall but I'll leave that for another ticket.