简体   繁体   中英

C++ call function by string, compare performance with PHP, how to optimize code in C++?

I am going to write a program that can let us to call function with string in C++. However, I wrote a program with same behavior in PHP, but PHP only took 4 seconds and finish executing, however, C++ took 27~28 seconds to finish. I wonder why PHP much faster than C++, and how to optimize the C++ code.

PS I am using Qt API, so the class name with prefix 'Q' such as QHash, QObject are classes from Qt.

Here are my code:

C++ code:

class header definition:

// function_dispatcher.h

#ifndef FUNCTIONDISPATCHER_H
#define FUNCTIONDISPATCHER_H

#include <QObject>
#include <QHash>
#include <functional>

class FunctionDispatcher : public QObject
{
    Q_OBJECT
public:
    FunctionDispatcher(QObject* parent = 0);
    int functionDispatcher(QString functionName, int dataA, int dataB);
    int function1(int a, int b);
    int function2(int a, int b);
    int function3(int a, int b);
    int function4(int a, int b);
    int function5(int a, int b);
    int function6(int a, int b);
    int function7(int a, int b);
    int function8(int a, int b);
    int function9(int a, int b);
    int function10(int a, int b);
    void functionTable();
private:
    QHash<QString, std::function<int(int, int)>> m_functionsTable;
};

#endif // FUNCTIONDISPATCHER_H

class body definition:

#include "functiondispatcher.h"
#include <QDebug>
#include <functional>

#define ADD_FUNCTION(_functionName, _function) m_functionsTable.insert(_functionName, std::bind(_function, this, std::placeholders::_1, std::placeholders::_2));

FunctionDispatcher::FunctionDispatcher(QObject *parent)
    : QObject(parent)
{
        functionTable();
}

int FunctionDispatcher::functionDispatcher(QString functionName, int dataA, int dataB)
{
    std::function<int(int, int)> func = m_functionsTable.value(functionName);
    int result = 0;
    try {
            result = func(dataA, dataB);
    }
    catch(const std::bad_function_call& e) {
            qDebug() << e.what();
    }

    return result;
}

int FunctionDispatcher::function1(int a, int b)
{
    return a + b;
}

int FunctionDispatcher::function2(int a, int b)
{
    return a * b;
}

int FunctionDispatcher::function3(int a, int b)
{
    return a / b;
}

int FunctionDispatcher::function4(int a, int b)
{
    return (a+12) * b;
}

int FunctionDispatcher::function5(int a, int b)
{
    return (a+1) * b;
}

int FunctionDispatcher::function6(int a, int b)
{
    return (a+2221) * b;
}

int FunctionDispatcher::function7(int a, int b)
{
    return (a+31) * b;
}

int FunctionDispatcher::function8(int a, int b)
{
    return (a+11) * b;
}

int FunctionDispatcher::function9(int a, int b)
{
    return (a+141) * b;
}

int FunctionDispatcher::function10(int a, int b)
{
    return (a+12) * b;
}

void FunctionDispatcher::functionTable()
{
    ADD_FUNCTION("function1", &FunctionDispatcher::function1);
    ADD_FUNCTION("function2", &FunctionDispatcher::function2);
    ADD_FUNCTION("function3", &FunctionDispatcher::function3);
    ADD_FUNCTION("function4", &FunctionDispatcher::function4);
    ADD_FUNCTION("function5", &FunctionDispatcher::function5);
    ADD_FUNCTION("function6", &FunctionDispatcher::function6);
    ADD_FUNCTION("function7", &FunctionDispatcher::function7);
    ADD_FUNCTION("function8", &FunctionDispatcher::function8);
    ADD_FUNCTION("function9", &FunctionDispatcher::function9);
    ADD_FUNCTION("function10", &FunctionDispatcher::function10);
}

and main function here:

#include <QCoreApplication>
#include "functiondispatcher.h"
#include <ctime>
#include <QDebug>
#include <iostream>

int main(int argc, char *argv[])
{

    time_t t1 = time(NULL);

    for (int i = 0; i < 10000000; i ++) {
        FunctionDispatcher *f = new FunctionDispatcher();
        f->functionDispatcher("function1", i, i + 1);
        f->functionDispatcher("function2", i, i + 1);
        f->functionDispatcher("function3", i, i + 1);
        f->functionDispatcher("function4", i, i + 1);
        f->functionDispatcher("function5", i, i + 1);
        f->functionDispatcher("function6", i, i + 1);
        f->functionDispatcher("function7", i, i + 1);
        f->functionDispatcher("function8", i, i + 1);
        f->functionDispatcher("function9", i, i + 1);
        f->functionDispatcher("function10", i, i + 1);
        delete f;
    }
    time_t t2 = time(NULL);

    qDebug() << t2 - t1;
}

PHP code:

<?php
class Dispatcher
{
        public function function1($a, $b)
        {
                return $a + $b;
        }
        public function function2($a, $b)
        {
                return $a * $b;
        }
        public function function3($a, $b)
        {
                return $a / $b;
        }
        public function function4($a, $b)
        {
                return ($a + 1) * ($b + 1);
        }
        public function function5($a, $b)
        {
                return $a / $b;
        }
        public function function6($a, $b)
        {
                return $a / $b;
        }
        public function function7($a, $b)
        {
                return $a / $b;
        }
        public function function8($a, $b)
        {
                return $a / $b;
        }
        public function function9($a, $b)
        {
                return $a / $b;
        }
        public function function10($a, $b)
        {
                return $a / $b;
        }
}
$time1 = time();
for ($i = 0; $i <= 10000000; $i ++)
{
        $function = new Dispatcher();
        $function->{"function1"}($i, $i + 1);
        $function->{"function2"}($i, $i + 1);
        $function->{"function3"}($i, $i + 1);
        $function->{"function4"}($i, $i + 1);
        $function->{"function5"}($i, $i + 1);
        $function->{"function6"}($i, $i + 1);
        $function->{"function7"}($i, $i + 1);
        $function->{"function8"}($i, $i + 1);
        $function->{"function9"}($i, $i + 1);
        $function->{"function10"}($i, $i + 1);
}
$time2 = time();
echo $time2 - $time1;

DO NOT use std::function . Use function pointer instead.

std::function is a wrapper of ANY Callable target including functions, functor, lambda expression etc. It is so heavy and you don't need it in your situation .

Then make sure you turn on the -O2 (or even -O3 ) option when compiling.

Probably you should use const references at some places.

int FunctionDispatcher::functionDispatcher(const QString& functionName, int dataA, int dataB)
{
    const std::function<int(int, int)>& func = m_functionsTable.value(functionName);
    int result = 0;
    try {
            result = func(dataA, dataB);
    }
    catch(const std::bad_function_call& e) {
            qDebug() << e.what();
    }

    return result;
}

might perhaps already increase performance a lot. Call by value is usually much slower in C++ than to do it with references. Also, your local func variable doesn't need to be a copy.

My final solution is:

I split Dispatcher from Controller and build functionsTable only one time, and I use function pointer point to call function.

#include <iostream>
#include <ctime>
#include <map>

class Controller
{
public:
        int function1(int a, int b) {return a + b;}
        int function2(int a, int b) {return a + b;}
        int function3(int a, int b) {return a * b;}
        int function4(int a, int b) {return a + 50 + b/2;}
        int function5(int a, int b) {return a + b;}
        int function6(int a, int b) {return a / 2 + b;}
        int function7(int a, int b) {return a + b * 19;}
        int function8(int a, int b) {return a + b * 20;}
        int function9(int a, int b) {return a + b + 100;}
        int function10(int a, int b) {return a / b;}
};

typedef int (Controller::*function)(int a, int b);

class Dispatcher
{
public:
        Dispatcher()
        {
                m_functionsTable.insert(std::pair<std::string, function>("function1", &Controller::function1));
                m_functionsTable.insert(std::pair<std::string, function>("function2", &Controller::function2));
                m_functionsTable.insert(std::pair<std::string, function>("function3", &Controller::function3));
                m_functionsTable.insert(std::pair<std::string, function>("function4", &Controller::function4));
                m_functionsTable.insert(std::pair<std::string, function>("function5", &Controller::function5));
                m_functionsTable.insert(std::pair<std::string, function>("function6", &Controller::function6));
                m_functionsTable.insert(std::pair<std::string, function>("function7", &Controller::function7));
                m_functionsTable.insert(std::pair<std::string, function>("function8", &Controller::function8));
                m_functionsTable.insert(std::pair<std::string, function>("function9", &Controller::function9));
                m_functionsTable.insert(std::pair<std::string, function>("function10", &Controller::function10));
        }
        int FunctionDispatcher(std::string functionName, int a, int b) {
                Controller c;
                function f = m_functionsTable.find(functionName)->second;
                return (c.*(function)f)(a, b);
        }
private:
        std::map<std::string, function> m_functionsTable;
};


int main()
{

        time_t t1 = time(NULL);

        Dispatcher d;
        for (int i = 0; i < 10000000; i ++) {
                d.FunctionDispatcher("function1", i, i + 1);
                d.FunctionDispatcher("function2", i, i + 1);
                d.FunctionDispatcher("function3", i, i + 1);
                d.FunctionDispatcher("function4", i, i + 1);
                d.FunctionDispatcher("function5", i, i + 1);
                d.FunctionDispatcher("function6", i, i + 1);
                d.FunctionDispatcher("function7", i, i + 1);
                d.FunctionDispatcher("function8", i, i + 1);
                d.FunctionDispatcher("function9", i, i + 1);
                d.FunctionDispatcher("function10", i, i + 1);

        }

        time_t t2 = time(NULL);
        std::cout << t2 - t1 << std::endl;
}

This solution took 3 seconds to run the program.

If I increase the loop from 10 million times to 100 million times, it only took 21 second, but PHP took 41 seconds.

My execution environment:

  • E3-1230 v5
  • 16GB DDR4
  • 256GB SATA3 SSD

I upload the code to "ideone", and it shown that the program only took 5 seconds. link here: https://ideone.com/7DUXYG

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM