Skip to content

Commit cd45a7a

Browse files
committed
add event_loop doc
1 parent b3a0bc5 commit cd45a7a

File tree

1 file changed

+84
-0
lines changed

1 file changed

+84
-0
lines changed

doc/reference/eventloop.qbk

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
[chapter Event Loop
2+
[quickbook 1.7]
3+
]
4+
5+
[section boost/python/eventloop.hpp]
6+
7+
[section Introduction]
8+
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.
9+
[endsect]
10+
11+
[section Function `set_default_event_loop`]
12+
``
13+
void set_default_event_loop(const boost::asio::io_context::strand& strand);
14+
``
15+
[variablelist
16+
[[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]]
17+
[[Throws][nothing]]
18+
]
19+
[endsect]
20+
21+
[section Function `PyInit_boost_event_loop`]
22+
``
23+
extern "C"
24+
{
25+
PyObject* PyInit_boost_event_loop();
26+
}
27+
``
28+
[variablelist
29+
[[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`]]]
30+
[[Throws][nothing]]
31+
]
32+
[endsect]
33+
34+
[section Example]
35+
``
36+
// example.cpp
37+
io_context ctx;
38+
io_context::strand st{ctx};
39+
40+
PyImport_AppendInittab("boost_event_loop", &PyInit_boost_event_loop);
41+
Py_Initialize();
42+
set_default_event_loop(st);
43+
44+
object py_module = import("example.py");
45+
py_module.attr("hello_world")();
46+
st.context().run();
47+
48+
// example.py
49+
import asyncio
50+
def hello_world():
51+
print("hello world")
52+
53+
def call_event_loop():
54+
loop = asyncio.get_event_loop_policy().get_event_loop()
55+
loop.call_soon(hello_world)
56+
``
57+
[endsect]
58+
59+
[section Event Loop and Multiple Python Sub-interpreters]
60+
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.
61+
[endsect]
62+
63+
[section Create, Swap, and Destroy Sub-interpreter]
64+
One way to create an interpreter is
65+
``
66+
PyThreadState* ts = PyThreadState_Swap(Py_NewInterpreter());
67+
``
68+
This will create an interpreter and its first thread.[br]
69+
Call [@https://docs.python.org/3/c-api/init.html#c.PyThreadState_Swap `PyThreadState_Swap`] to swap between different interpreter.[br]
70+
To destroy an interpreter, simply call
71+
``
72+
// this will destroy the interpreter and switch to other_ts
73+
Py_EndInterpreter(ts);
74+
PyThreadState_Swap(other_ts);
75+
``
76+
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]
77+
[@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.
78+
[endsect]
79+
80+
[section [@https://docs.python.org/3/c-api/init.html#thread-state-and-the-global-interpreter-lock `GIL`]]
81+
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.
82+
[endsect]
83+
84+
[endsect]

0 commit comments

Comments
 (0)