-
Notifications
You must be signed in to change notification settings - Fork 207
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
b3a0bc5
commit cd45a7a
Showing
1 changed file
with
84 additions
and
0 deletions.
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,84 @@ | ||
[chapter Event Loop | ||
[quickbook 1.7] | ||
] | ||
|
||
[section boost/python/eventloop.hpp] | ||
|
||
[section Introduction] | ||
Provide a Boost.Asio-based implementation for the Python [@https://docs.python.org/3/library/asyncio-eventloop.html `EventLoop`] type. Every callback is scheduled in strand. | ||
[endsect] | ||
|
||
[section Function `set_default_event_loop`] | ||
`` | ||
void set_default_event_loop(const boost::asio::io_context::strand& strand); | ||
`` | ||
[variablelist | ||
[[Effect][construct an `event_loop` object using provided [@https://www.boost.org/doc/libs/1_76_0/doc/html/boost_asio/overview/core/strands.html `strand`] object. Setup a new [@https://docs.python.org/3/library/asyncio-policy.html event loop policy], when user call `get_event_loop` using that policy, it returns the Boost Asio `event_loop` object]] | ||
[[Throws][nothing]] | ||
] | ||
[endsect] | ||
|
||
[section Function `PyInit_boost_event_loop`] | ||
`` | ||
extern "C" | ||
{ | ||
PyObject* PyInit_boost_event_loop(); | ||
} | ||
`` | ||
[variablelist | ||
[[Effect][user must call `PyImport_AppendInittab("boost_event_loop", &PyInit_boost_event_loop);` before [@https://docs.python.org/3/c-api/init.html#c.Py_Initialize `Py_Initialize`]]] | ||
[[Throws][nothing]] | ||
] | ||
[endsect] | ||
|
||
[section Example] | ||
`` | ||
// example.cpp | ||
io_context ctx; | ||
io_context::strand st{ctx}; | ||
|
||
PyImport_AppendInittab("boost_event_loop", &PyInit_boost_event_loop); | ||
Py_Initialize(); | ||
set_default_event_loop(st); | ||
|
||
object py_module = import("example.py"); | ||
py_module.attr("hello_world")(); | ||
st.context().run(); | ||
|
||
// example.py | ||
import asyncio | ||
def hello_world(): | ||
print("hello world") | ||
|
||
def call_event_loop(): | ||
loop = asyncio.get_event_loop_policy().get_event_loop() | ||
loop.call_soon(hello_world) | ||
`` | ||
[endsect] | ||
|
||
[section Event Loop and Multiple Python Sub-interpreters] | ||
It's allowed to have multiple Python sub-interpreter instances in a same program. Each interpreter will act as a guest VM, and C++ host will schedule all the asynchronous events committed by the Python VM. | ||
[endsect] | ||
|
||
[section Create, Swap, and Destroy Sub-interpreter] | ||
One way to create an interpreter is | ||
`` | ||
PyThreadState* ts = PyThreadState_Swap(Py_NewInterpreter()); | ||
`` | ||
This will create an interpreter and its first thread.[br] | ||
Call [@https://docs.python.org/3/c-api/init.html#c.PyThreadState_Swap `PyThreadState_Swap`] to swap between different interpreter.[br] | ||
To destroy an interpreter, simply call | ||
`` | ||
// this will destroy the interpreter and switch to other_ts | ||
Py_EndInterpreter(ts); | ||
PyThreadState_Swap(other_ts); | ||
`` | ||
The Python interpreter must outlive the [@https://www.boost.org/doc/libs/1_76_0/doc/html/boost_asio/reference/io_service.html `asio::io_context`] objects it owns. It's not safe to destroy the interpreter midways.[br] | ||
[@https://docs.python.org/3/c-api/structures.html#c.PyObject `PyObject`] [@https://docs.python.org/3/c-api/refcounting.html `reference count`] won't protect its interpreter from being destroyed. | ||
[endsect] | ||
|
||
[section [@https://docs.python.org/3/c-api/init.html#thread-state-and-the-global-interpreter-lock `GIL`]] | ||
GIL is shared by all sub-interpreters in the same program, which means after setting up the Python IO object and call the async functions, C++ host should release the GIL of current interpreter. | ||
[endsect] | ||
|
||
[endsect] |