Last active
March 2, 2025 23:01
-
-
Save tritao/8dcf93adc14fab1dc4c39de382d8d9c4 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
#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; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
g++ -std=c++11 py-asyncio-compute.cpp $(python3.12-config --includes --cflags --ldflags) -lpython3.12