3

I have a python script that I need to call lots of times (around 160000 times) and while I can do this in less that a second with hard C++ code, if I try to load and call a python script to do this, it will probably take hours! I think that if I loaded the script once, then run the loaded script over and over, it will be significantly faster. Unfortunately, I don't know how to do this. I don't think I can load the file with ifstream, then use PyRun_SimpleString on all the lines of the string. In case it isn't faster however, is it possible to return a 2D array in python, then convert that Array into a std::vector?

Ben Hollier
  • 585
  • 2
  • 11
  • 32
  • How are the inputs to your script determined? Your suggestion of using `PyRun_SimpleString` implies that you are not passing any arguments to the script from your C++ code. If that's not the case, what is changing between invocations of your script? – Nasser Al-Shawwa Jul 08 '15 at 12:27
  • @Nasser The script does have inputs, which are parameters into a function. I call the function with `PyObject_CallFunction`. The only reason I mentioned `PyRun_SimpleString` was so people didn't assume I've done no research. – Ben Hollier Jul 08 '15 at 12:31

1 Answers1

5

Consider the following function, in a file called multiply.py

#!/usr/bin/python3

def do_multiply(a, b):
    c = 0
    for i in range(0, a):
        c += b
    return c

In your C++ file:

// Load the function 
PyObject *pName     = PyUnicode_FromString("multiply");
PyObject *pModule   = PyImport_Import(pName);
PyObject *pFunction = PyObject_GetAttrString(pModule, "do_multiply")

Let's say you want to call this function 3 times, as follows:

struct NumberPair 
{ 
    int x;
    int y;
};

std::vector<NumberPair> numberPairs { {1, 2}, {5, 6}, {10, 12} };

Then, you can simply call PyObject_CallFunction several times, while the module is loaded:

for(const auto &numberPair : numberPairs)
{
    PyObject *product = PyObject_CallFunction(pFunction, "ii", numberPair.x, numberPair.y);
    if(product != NULL)
    {
        std::cout << "Product is " << PyLong_AsLong(product) << '\n';
        Py_DECREF(product);
    }
}

There is no need to close the module between calls to PyObject_CallFunction, so that shouldn't be a problem.

Nasser Al-Shawwa
  • 3,573
  • 17
  • 27
  • I imagine this answer was very obvious, and I look like an idiot. It wouldn't be the first time I over thought something to do with programming, thank you for the answer! – Ben Hollier Jul 08 '15 at 12:58
  • Anytime! Please note the edit I made for de-allocating memory where necessary in the loop. – Nasser Al-Shawwa Jul 08 '15 at 13:01