-
Notifications
You must be signed in to change notification settings - Fork 50
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
added goroutines example #5
base: master
Are you sure you want to change the base?
Conversation
…d line breaks in Printf
@esendjer thanks for working on this! Much appreciated. Could you please review your Go code and make sure that:
For example for
(If you need more explanation on the memory handling, I wrote a blogpost here). Let me know when done and I'll continue to review. Thanks! |
@christian-korneck thanks for your points and advice. Thanks! |
a PyObject shouldn't get decref'ed before you know for sure that you actually got a PyObject that needs decref'ing. |
Got it. Thanks. I'll fix this. |
In the last commit, I decided to stop using If I understood well it happens because so is the logic of working Py_FinalizeEx/Py_Finalize. According to the article https://docs.python.org/3/c-api/init.html#c.Py_FinalizeEx: Instead applying nameModule := "foo"
fooModule := python3.PyImport_ImportModule(nameModule)
if fooModule == nil && python3.PyErr_Occurred() != nil {
err = errors.New("Error importing the python module")
fooModule.DecRef()
return
} Sorry for lots of attention and some mistakes, I'm just a beginner 😔 |
@esendjer no worries, that's okay.
The main challenge of this task is to get everything "correct" and being relatively certain about it. This requires understanding of how memory management with the CPython C-API works, amongst other things (GIL, etc). If you want to move on with this task (I highly encourage you to do so, there's lots to learn), I would suggest that you take the time and familiarize yourself with this topic area. For example you could start by using the blogpost/tutorial that I've mentioned above as a first tutorial, then write a few programs, etc and make sure you understand them and are able to debug them. You will likely need to consult other docs, etc as well (docs and examples are usually for C but translate well into Go). If you have any specific questions feel free to ask. (Also stackoverflow, etc are good places if you stick to C, if that's an option for you). For this PR: I'll continue to review if/when you're confident that your code is "correct". Also just to say, there's no rush. I don't think anyone else is working on this. Take your time. (However, I could also understand if this doesn't work for you - feel free to close the PR in that case). |
…right working with references and its decrement
Thanks a ton for your explanation and your article, and sorry for missing some important points from it. As I see now, my issue was in that I tried to decrement the reference count for the I've fixed this issue, turned back using |
Thanks. Before I review it, could you go over it, check for the usual things and improve the code if needed?
|
Thank you. I'll continue working on this point-by-point. And thanks a lot for the useful links. I'm a bit confused about the 2nd point - There are a few places where the code works with the GIL: // Initialize the Python interpreter and
// since version 3.7 it also creates the GIL explicitly by calling PyEval_InitThreads()
// so you don’t have to call PyEval_InitThreads() yourself anymore
python3.Py_Initialize() // <-- create the GIL, the GIL is locked by the main thread
// ... Following is importing of Python module
// and declaration of variables, getting attributes
// and others action of creating/defining of PyObject
// Save the current state and release the GIL
// so that goroutines can acquire it
state := python3.PyEval_SaveThread() // <-- release the GIL, the GIL is unlocked for using by goroutines
// the 1st goroutine
go func() {
_gstate := python3.PyGILState_Ensure() // <-- acquire the GIL, the GIL is locked by the 1st goroutine
// ... call python code
python3.PyGILState_Release(_gstate) // <-- release the GIL, the GIL is unlocked for using by others
// ...
}()
// the 2nd goroutine
go func() {
_gstate := python3.PyGILState_Ensure() // <-- acquire the GIL, the GIL is locked by the 2nd goroutine
// ... call python code
python3.PyGILState_Release(_gstate) // <-- release the GIL, the GIL is unlocked for using by others
// ...
}()
// Restore the state and lock the GIL
python3.PyEval_RestoreThread(state) // <-- acquire the GIL, the GIL is locked by the main thread Here I follow the next pattern of embedding Python code:
And for each locking here is releasing, in the end, the lock is returned to the main thread Unfortunately, I have no idea how yet I can be sure more of the correctness of the GIL locking/unlocking. I think I can add some checks with |
this was just meant in a very generic way. The code must not have bugs or flaws in that aspect (as it's supposed to be an example for it). I haven't really looked at your code yet and it's not meant as critic of something specific. |
Thanks! Now, this point is clear to me. |
I went through the checklist and tried to cover so many points as possible.
|
Thanks for this. Just as a quick heads up: I'm currently a bit slow to respond, but will look at this PR soon. Thanks for your patience! |
there are also some problems when the go-routine is scheduled to another thread,see this page: https://studygolang.com/articles/12822. |
hi team, I have a program where I want to DecRef a PyObject(the return value of python methods) in a go routine. The code inside go routine looks something like this: (... redacted by moderator and moved to github discussions: #16 (comment)) |
@jshiwam and everyone - just to do some housekeeping: I don't think this PR discussion is the best place for your comment. Why? Well it's a question about a specific code problem that you're having and not really concret feedback or suggestions about the PR that @esendjer is crafting. We're relatively liberal about allowing usage questions as issues here, even if they have little or nothing to do with this project (which is just a thin Go wrapper around the CPython C-API), but are often really CPython C-API usage questions. But issues and PRs should still stay on topic. As we're seeing usage questions from time to time, I have now enabled Github Discussions, with a "Usage Discussion" section: I hope this allows us to:
@jshiwam That's why I've redacted your above comment and moved your full question to Github Discussions and posted a first reply to it: |
} | ||
|
||
args := python3.PyTuple_New(1) // new reference, a call DecRef() is needed | ||
if args == nil && python3.PyErr_Occurred() != nil { |
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.
docs for PyTuple_New
don't mention a Python error gets raised on failure, so this should probably only be a check for NULL?
(When an error gets raised on failure usually the docs say something like Return <something good>, or NULL with an exception set on failure
. But not here).
@christian-korneck @esendjer if no one is working on this PR then I can take this up and finish it, as these examples are really important for people who use this wrapper lib. |
@jshiwam sure, all input is welcome! |
Hi @christian-korneck sorry for the delayed response, had been busy recently. I have made the final changes in this code. According to my understanding only using |
Here please check it out. |
What does this PR do?
Adding an example of using goroutines
Motivation
The issue #4
Additional Notes
This example is up to date and tested