Skip to content

Instantly share code, notes, and snippets.

@tritao
Last active March 2, 2025 23:01
Show Gist options
  • Save tritao/8dcf93adc14fab1dc4c39de382d8d9c4 to your computer and use it in GitHub Desktop.
Save tritao/8dcf93adc14fab1dc4c39de382d8d9c4 to your computer and use it in GitHub Desktop.
#include <Python.h>
#include <thread>
#include <future>
#include <iostream>
#include <chrono>
// ----- Python-bound Function: execute -----
//
// This function takes an integer, offloads a computation (here, squaring the number)
// using std::async, and returns the result.
static PyObject* execute(PyObject* self, PyObject* args) {
int input;
if (!PyArg_ParseTuple(args, "i", &input)) {
return nullptr;
}
int result = 0;
// Release the GIL so that the asynchronous computation can run in parallel.
Py_BEGIN_ALLOW_THREADS
// Launch the computation asynchronously.
auto future_result = std::async(std::launch::async, [input]() -> int {
// Simulate a compute-intensive task.
std::this_thread::sleep_for(std::chrono::milliseconds(100));
return input * input;
});
result = future_result.get();
Py_END_ALLOW_THREADS
return PyLong_FromLong(result);
}
// ----- Module Definition -----
static PyMethodDef MyModuleMethods[] = {
{"execute", execute, METH_VARARGS, "Execute a computation and return the result."},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef mymodule = {
PyModuleDef_HEAD_INIT,
"mymodule", // Module name
NULL, // Module documentation (can be NULL)
-1, // Size of per-interpreter state of the module
MyModuleMethods
};
PyMODINIT_FUNC PyInit_mymodule(void) {
return PyModule_Create(&mymodule);
}
// ----- Function to Run Python Script in a Dedicated Thread -----
//
// This function registers our module, initializes Python, and runs a script.
// The script uses asyncio to call our bound "execute" function concurrently.
void runPythonScript() {
// Register our module before initializing the interpreter.
if (PyImport_AppendInittab("mymodule", PyInit_mymodule) == -1) {
std::cerr << "Error: could not extend in-built modules table\n";
return;
}
// Initialize the Python interpreter.
Py_Initialize();
// Import our module so it's available in the script.
PyImport_ImportModule("mymodule");
// Define a Python script that uses asyncio to call our execute function.
const char* script = R"(
import asyncio
import mymodule
async def async_execute(x):
result = mymodule.execute(x)
print(f"Result for {x}: {result}")
return result
async def main():
tasks = [async_execute(i) for i in range(5)]
results = await asyncio.gather(*tasks)
print("All results:", results)
if __name__ == '__main__':
asyncio.run(main())
)";
// Run the script.
PyRun_SimpleString(script);
// Finalize the interpreter.
Py_Finalize();
}
//
// ----- Main: Start the Python Thread -----
//
int main() {
// Start the Python interpreter in its own thread.
std::thread pythonThread(runPythonScript);
// Wait for the Python thread to finish.
pythonThread.join();
return 0;
}
@tritao
Copy link
Author

tritao commented Mar 2, 2025

g++ -std=c++11 py-asyncio-compute.cpp $(python3.12-config --includes --cflags --ldflags) -lpython3.12

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment