forked from DataDog/go-python3
-
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
Open
esendjer
wants to merge
7
commits into
go-python:master
Choose a base branch
from
esendjer:master
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
076452f
added goroutines example
esendjer c871e09
a little fix: Moved the name of foo python module to a variable. Adde…
esendjer e6a8b56
Updated according to the comment - https://github.com/go-python/cpy3/…
esendjer 896499b
fixed using the DecRef() of python objects in defer statements
esendjer a9c6933
fixed the problem with random panic on a call Py_Finalize due to not …
esendjer 2f094fc
Fixed comment. Reached to idiomatic as possible. Applied linters.
esendjer 191bf33
Used log instead fmt for printing error messages
esendjer File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import sys | ||
|
||
def print_odds(limit=10): | ||
""" | ||
Print odds numbers < limit | ||
""" | ||
for i in range(limit): | ||
if i%2: | ||
sys.stderr.write("odds: {}\n".format(i)) | ||
|
||
def print_even(limit=10): | ||
""" | ||
Print even numbers < limit | ||
""" | ||
for i in range(limit): | ||
if i%2 == 0: | ||
sys.stderr.write("even: {}\n".format(i)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
package main | ||
|
||
import ( | ||
"errors" | ||
"log" | ||
"os" | ||
"sync" | ||
|
||
python3 "github.com/go-python/cpy3" | ||
) | ||
|
||
func main() { | ||
var err error | ||
|
||
// At the end of all, if there was an error | ||
// prints the error and exit with the non-zero code | ||
defer func() { | ||
if err != nil { | ||
log.Printf("%+v", err) | ||
os.Exit(1) | ||
} | ||
}() | ||
|
||
// Undo all initializations made by Py_Initialize() and subsequent | ||
defer python3.Py_Finalize() | ||
|
||
// Prints any python error if it was here | ||
// no needs to call it after each single check of PyErr_Occurred() | ||
defer python3.PyErr_Print() | ||
|
||
// Initialize the Python interpreter and | ||
// since version 3.7 it also create 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 | ||
|
||
if !python3.Py_IsInitialized() { | ||
err = errors.New("error initializing the python interpreter") | ||
return | ||
} | ||
|
||
var wg sync.WaitGroup | ||
wg.Add(2) | ||
|
||
fooModule := python3.PyImport_ImportModule("foo") // new reference, a call DecRef() is needed | ||
if fooModule == nil && python3.PyErr_Occurred() != nil { | ||
err = errors.New("error importing the python module") | ||
return | ||
} | ||
defer fooModule.DecRef() | ||
|
||
odds := fooModule.GetAttrString("print_odds") // new reference, a call DecRef() is needed | ||
if odds == nil && python3.PyErr_Occurred() != nil { | ||
err = errors.New("error getting the attribute print_odds") | ||
return | ||
} | ||
defer odds.DecRef() | ||
|
||
even := fooModule.GetAttrString("print_even") // new reference, a call DecRef() is needed | ||
if even == nil && python3.PyErr_Occurred() != nil { | ||
err = errors.New("error getting the attribute print_even") | ||
return | ||
} | ||
defer even.DecRef() | ||
|
||
limit := python3.PyLong_FromGoInt(50) // new reference, will stolen later, a call DecRef() is NOT needed | ||
if limit == nil && python3.PyErr_Occurred() != nil { | ||
err = errors.New("error creating python long object") | ||
return | ||
} | ||
|
||
args := python3.PyTuple_New(1) // new reference, a call DecRef() is needed | ||
if args == nil && python3.PyErr_Occurred() != nil { | ||
err = errors.New("error creating python tuple object") | ||
return | ||
} | ||
defer args.DecRef() | ||
|
||
ret := python3.PyTuple_SetItem(args, 0, limit) // steals reference to limit | ||
|
||
// Cleans the Go variable, because now a new owner is caring about related PyObject | ||
// no action, such as a call DecRef(), is needed here | ||
limit = nil | ||
|
||
if ret != 0 { | ||
err = errors.New("error setting a tuple item") | ||
limit.DecRef() | ||
limit = nil | ||
return | ||
} | ||
|
||
// 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 | ||
|
||
go func() { | ||
_gstate := python3.PyGILState_Ensure() // acquire the GIL, the GIL is locked by the 1st goroutine | ||
odds.Call(args, python3.PyDict_New()) | ||
python3.PyGILState_Release(_gstate) // release the GIL, the GIL is unlocked for using by others | ||
|
||
wg.Done() | ||
}() | ||
|
||
go func() { | ||
_gstate := python3.PyGILState_Ensure() // acquire the GIL, the GIL is locked by the 2nd goroutine | ||
even.Call(args, python3.PyDict_New()) | ||
python3.PyGILState_Release(_gstate) // release the GIL, the GIL is unlocked for using by others | ||
|
||
wg.Done() | ||
}() | ||
|
||
wg.Wait() | ||
|
||
// Restore the state and lock the GIL | ||
python3.PyEval_RestoreThread(state) // acquire the GIL, the GIL is locked by the main thread | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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).