performance - PHP 5 प्रतिबिंब एपीआई प्रदर्शन




reflection (9)

कभी-कभी कॉल_user_func_array () जैसी किसी चीज़ का उपयोग करके आपको वह चाहिए जो आपको चाहिए। पता नहीं कैसे प्रदर्शन अलग है।

मैं वर्तमान में अपने स्वयं के एमवीसी वेब ढांचे में प्रतिबिंब वर्ग (प्रतिबिंब क्लास और प्रतिबिंब विधि मुख्य रूप से) के उपयोग पर विचार कर रहा हूं, क्योंकि मुझे स्वचालित रूप से नियंत्रक वर्गों को कम करने और किसी भी आवश्यक कॉन्फ़िगरेशन ("कॉन्फ़िगरेशन पर सम्मेलन" दृष्टिकोण) के बिना अपने तरीकों का आह्वान करने की आवश्यकता है।

मैं प्रदर्शन के बारे में चिंतित हूं, भले ही मुझे लगता है कि डेटाबेस अनुरोध वास्तविक PHP कोड की तुलना में बड़ी बाधाओं की संभावना है।

तो, मैं सोच रहा हूं कि किसी के पास प्रदर्शन के दृष्टिकोण से PHP 5 प्रतिबिंब के साथ कोई अच्छा या बुरा अनुभव है।

इसके अलावा, मुझे यह जानकर उत्सुकता होगी कि क्या किसी भी लोकप्रिय PHP ढांचे (सीआई, केक, सिम्फनी, आदि) वास्तव में प्रतिबिंब का उपयोग करते हैं।


कोड पर आधारित @ एलिक्स एक्सेल प्रदान किया गया

तो पूर्णता के लिए मैंने कक्षा में प्रत्येक विकल्प को लपेटने का फैसला किया और लागू होने वाले ऑब्जेक्ट्स के कैशिंग को शामिल किया। यहां परिणाम और कोड थे i7-4710HQ पर PHP 5.6 पर परिणाम

array (
  'Direct' => '5.18932366',
  'Variable' => '5.62969398',
  'Reflective' => '6.59285069',
  'User' => '7.40568614',
)

कोड:

function Benchmark($callbacks, $iterations = 100, $relative = false)
{
    set_time_limit(0);

    if (count($callbacks = array_filter((array) $callbacks, 'is_callable')) > 0)
    {
        $result = array_fill_keys(array_keys($callbacks), 0);
        $arguments = array_slice(func_get_args(), 3);

        for ($i = 0; $i < $iterations; ++$i)
        {
            foreach ($result as $key => $value)
            {
                $value = microtime(true); call_user_func_array($callbacks[$key], $arguments); $result[$key] += microtime(true) - $value;
            }
        }

        asort($result, SORT_NUMERIC);

        foreach (array_reverse($result) as $key => $value)
        {
            if ($relative === true)
            {
                $value /= reset($result);
            }

            $result[$key] = number_format($value, 8, '.', '');
        }

        return $result;
    }

    return false;
}

class foo {
    public static function bar() {
        return __METHOD__;
    }
}

class TesterDirect {
    public function test() {
        return foo::bar($_SERVER['REQUEST_TIME']);
    }
}

class TesterVariable {
    private $class = 'foo';

    public function test() {
        $class = $this->class;

        return $class::bar($_SERVER['REQUEST_TIME']);
    }
}

class TesterUser {
    private $method = array('foo', 'bar');

    public function test() {
        return call_user_func($this->method, $_SERVER['REQUEST_TIME']);
    }
}

class TesterReflective {
    private $class = 'foo';
    private $reflectionMethod;

    public function __construct() {
        $this->reflectionMethod = new ReflectionMethod($this->class, 'bar');
    }

    public function test() {
        return $this->reflectionMethod->invoke(null, $_SERVER['REQUEST_TIME']);
    }
}

$testerDirect = new TesterDirect();
$testerVariable = new TesterVariable();
$testerUser = new TesterUser();
$testerReflective = new TesterReflective();

fputs(STDOUT, var_export(Benchmark(array(
    'Direct' => array($testerDirect, 'test'),
    'Variable' => array($testerVariable, 'test'),
    'User' => array($testerUser, 'test'),
    'Reflective' => array($testerReflective, 'test')
), 10000000), true));

एक स्थिर कार्य को 1 मिलियन बार कॉल करने से मेरी मशीन पर ~ 0.31 सेकंड खर्च होंगे। प्रतिबिंब विधि का उपयोग करते समय, इसकी लागत ~ 1.82 सेकंड होती है। इसका मतलब है कि प्रतिबिंब एपीआई का उपयोग करने के लिए ~ 500% अधिक महंगा है।

यह वह कोड है जिसका मैंने उपयोग किया था:

<?PHP

class test
{
    static function f(){
            return;
    }
}

$s = microtime(true);
for ($i=0; $i<1000000; $i++)
{
    test::f('x');
}
echo ($a=microtime(true) - $s)."\n";

$s = microtime(true);
for ($i=0; $i<1000000; $i++)
{
    $rm = new ReflectionMethod('test', 'f');
    $rm->invokeArgs(null, array('f'));
}

echo ($b=microtime(true) - $s)."\n";

echo 100/$a*$b;

जाहिर है, वास्तविक प्रभाव उन कॉलों की संख्या पर निर्भर करता है जिन्हें आप उम्मीद करते हैं


इसके अलावा, मुझे यह जानकर उत्सुकता होगी कि क्या किसी भी लोकप्रिय PHP ढांचे (सीआई, केक, सिम्फनी, आदि) वास्तव में प्रतिबिंब का उपयोग करते हैं।

http://framework.zend.com/manual/en/zend.server.reflection.html

"आम तौर पर, यह कार्यक्षमता केवल ढांचे के लिए सर्वर कक्षाओं के डेवलपर्स द्वारा उपयोग की जाएगी।"


मैं कुछ नया चाहता था, तो इस रेपो पर एक नज़र डालें। सारांश से:

  • PHP 7 प्रतिबिंब के मामले में लगभग 5 गुना तेज है - यह सीधे संकेत नहीं देता है कि PHP7 पर प्रतिबिंब तेजी से हैं, PHP7 कोर को अभी एक महान अनुकूलन प्राप्त हुआ है और सभी कोड इससे लाभान्वित होंगे।
  • मूल प्रतिबिंब काफी तेज़ हैं - 1000 वर्गों के लिए पढ़ना विधियों और दस्तावेज़ टिप्पणियों की लागत केवल कुछ मिलीसेकंड है। क्लासफाइल को पार्सिंग / ऑटोलोडिंग वास्तविक प्रतिबिंब यांत्रिकी से बहुत अधिक समय लेता है। हमारे परीक्षण प्रणाली पर 1000 वर्ग फ़ाइलों को स्मृति (आवश्यकता / शामिल / ऑटोलोड) में लोड करने के लिए लगभग 300ms लगते हैं - और कक्षाओं की समान मात्रा में प्रतिबिंब पार्सिंग (डॉक्टर टिप्पणियां, getMethods, आदि ...) का उपयोग करने के लिए केवल 1-5ms से अधिक।
  • निष्कर्ष: प्रतिबिंब तेजी से होते हैं और सामान्य उपयोग मामलों में आप उस प्रदर्शन प्रभाव को अनदेखा कर सकते हैं। हालांकि, हमेशा जरूरी है कि केवल आवश्यकतानुसार विश्लेषण करें। और, कैशिंग प्रतिबिंब आपको प्रदर्शन पर कोई ध्यान देने योग्य लाभ नहीं देता है।

इसके अलावा, एक और बेंचमार्क देखें

उन परिणामों को PHP 5.5.5 का उपयोग कर विकास ओएस एक्स मशीन पर प्राप्त किया गया था। [...]

  • एक वस्तु पर एक ही संपत्ति पढ़ें: बंद थोड़ा तेज है।

  • कई वस्तुओं पर एक ही संपत्ति पढ़ें: प्रतिबिंब रास्ता तेज है।

  • किसी ऑब्जेक्ट के सभी गुणों को पढ़ना: बंद होना तेज है।

  • एक वस्तु पर एक ही संपत्ति लिखना: प्रतिबिंब थोड़ा तेज़ है।

  • कई वस्तुओं पर एक ही संपत्ति लिखना: प्रतिबिंब रास्ता तेज है।


कोडइग्निटर निश्चित रूप से प्रतिबिंब का उपयोग करता है। और मैं दूसरों को भी शर्त लगाता हूं। सीआई स्थापना में सिस्टम / नियंत्रक फ़ोल्डर में नियंत्रक वर्ग में देखें।


चिंतित मत हो। Xdebug स्थापित करें और सुनिश्चित करें कि बाधा कहाँ है।

प्रतिबिंब का उपयोग करने की लागत है, लेकिन क्या यह मायने रखता है कि आप क्या कर रहे हैं। यदि आप प्रतिबिंब का उपयोग कर नियंत्रक / अनुरोध प्रेषक को लागू करते हैं, तो यह प्रति अनुरोध केवल एक उपयोग है। बिल्कुल नगण्य।

यदि आप प्रतिबिंब का उपयोग करके अपनी ओआरएम परत लागू करते हैं, तो इसे प्रत्येक ऑब्जेक्ट या किसी भी संपत्ति तक पहुंच के लिए उपयोग करें, और सैकड़ों या हजारों ऑब्जेक्ट्स बनाएं, फिर यह महंगा हो सकता है।


ओवरहेड छोटा है इसलिए कोई बड़ा प्रदर्शन जुर्माना नहीं है जैसे डीबी, टेम्पलेट प्रसंस्करण इत्यादि प्रदर्शन की समस्याएं हैं, यह देखने के लिए कि यह कितनी तेज़ है, एक सरल कार्रवाई के साथ अपने ढांचे का परीक्षण करें।

उदाहरण के लिए कोड बेलो (फ्रंटकंट्रोलर) जो प्रतिबिंब का उपयोग करता है, यह कुछ मिलीसेकंड में नौकरियां करता है

<?php
require_once('sanitize.inc');

/**
 * MVC Controller
 *
 * This Class implements  MVC Controller part
 *
 * @package MVC
 * @subpackage Controller
 *
 */
class Controller {

    /**
     * Standard Controller constructor
     */
    static private $moduleName;
    static private $actionName;
    static private $params;

    /**
     * Don't allow construction of the controller (this is a singleton)
     *
     */
    private function __construct() {

    }

    /**
     * Don't allow cloning of the controller (this is a singleton)
     *
     */
    private function __clone() {

    }

    /**
     * Returns current module name
     *
     * @return string
     */
    function getModuleName() {
        return self :: $moduleName;
    }

    /**
     * Returns current module name
     *
     * @return string
     */
    function getActionName() {
        return self :: $actionName;
    }

    /**
     * Returns the subdomain of the request
     *
     * @return string
     */
    function getSubdomain() {
        return substr($_SERVER['HTTP_HOST'], 0, strpos($_SERVER['HTTP_HOST'], '.'));
    }

    function getParameters($moduleName = false, $actionName = false) {
        if ($moduleName === false or ( $moduleName === self :: $moduleName and $actionName === self :: $actionName )) {
            return self :: $params;
        } else {
            if ($actionName === false) {
                return false;
            } else {
                @include_once ( FRAMEWORK_PATH . '/modules/' . $moduleName . '.php' );
                $method = new ReflectionMethod('mod_' . $moduleName, $actionName);
                foreach ($method->getParameters() as $parameter) {
                    $parameters[$parameter->getName()] = null;
                }
                return $parameters;
            }
        }
    }

    /**
     * Redirect or direct to a action or default module action and parameters
     * it has the ability to http redirect to the specified action
     * internally used to direct to action
     *
     * @param string $moduleName
     * @param string $actionName
     * @param array $parameters
     * @param bool $http_redirect

     * @return bool
     */
    function redirect($moduleName, $actionName, $parameters = null, $http_redirect = false) {
        self :: $moduleName = $moduleName;
        self :: $actionName = $actionName;
        // We assume all will be ok
        $ok = true;

        @include_once ( PATH . '/modules/' . $moduleName . '.php' );

        // We check if the module's class really exists
        if (!class_exists('mod_' . $moduleName, false)) { // if the module does not exist route to module main
            @include_once ( PATH . '/modules/main.php' );
            $modClassName = 'mod_main';
            $module = new $modClassName();
            if (method_exists($module, $moduleName)) {
                self :: $moduleName = 'main';
                self :: $actionName = $moduleName;
                //$_PARAMS = explode( '/' , $_SERVER['REQUEST_URI'] );
                //unset($parameters[0]);
                //$parameters = array_slice($_PARAMS, 1, -1);
                $parameters = array_merge(array($actionName), $parameters); //add first parameter
            } else {
                $parameters = array($moduleName, $actionName) + $parameters;
                $actionName = 'index';
                $moduleName = 'main';
                self :: $moduleName = $moduleName;
                self :: $actionName = $actionName;
            }
        } else { //if the action does not exist route to action index
            @include_once ( PATH . '/modules/' . $moduleName . '.php' );
            $modClassName = 'mod_' . $moduleName;
            $module = new $modClassName();
            if (!method_exists($module, $actionName)) {
                $parameters = array_merge(array($actionName), $parameters); //add first parameter
                $actionName = 'index';
            }
            self :: $moduleName = $moduleName;
            self :: $actionName = $actionName;
        }
        if (empty($module)) {
            $modClassName = 'mod_' . self :: $moduleName;
            $module = new $modClassName();
        }

        $method = new ReflectionMethod('mod_' . self :: $moduleName, self :: $actionName);

        //sanitize and set method variables
        if (is_array($parameters)) {
            foreach ($method->getParameters() as $parameter) {
                $param = current($parameters);
                next($parameters);
                if ($parameter->isDefaultValueAvailable()) {
                    if ($param !== false) {
                        self :: $params[$parameter->getName()] = sanitizeOne(urldecode(trim($param)), $parameter->getDefaultValue());
                    } else {
                        self :: $params[$parameter->getName()] = null;
                    }
                } else {
                    if ($param !== false) {//check if variable is set, avoid notice
                        self :: $params[$parameter->getName()] = sanitizeOne(urldecode(trim($param)), 'str');
                    } else {
                        self :: $params[$parameter->getName()] = null;
                    }
                }
            }
        } else {
            foreach ($method->getParameters() as $parameter) {
                self :: $params[$parameter->getName()] = null;
            }
        }

        if ($http_redirect === false) {//no redirecting just call the action
            if (is_array(self :: $params)) {
                $method->invokeArgs($module, self :: $params);
            } else {
                $method->invoke($module);
            }
        } else {
            //generate the link to action
            if (is_array($parameters)) { // pass parameters
                $link = '/' . $moduleName . '/' . $actionName . '/' . implode('/', self :: $params);
            } else {
                $link = '/' . $moduleName . '/' . $actionName;
            }
            //redirect browser
            header('Location:' . $link);

            //if the browser does not support redirecting then provide a link to the action
            die('Your browser does not support redirect please click here <a href="' . $link . '">' . $link . '</a>');
        }
        return $ok;
    }

    /**
     * Redirects to action contained within current module
     */
    function redirectAction($actionName, $parameters) {
        self :: $actionName = $actionName;
        call_user_func_array(array(&$this, $actionName), $parameters);
    }

    public function module($moduleName) {
        self :: redirect($moduleName, $actionName, $parameters, $http_redirect = false);
    }

    /**
     * Processes the client's REQUEST_URI and handles module loading/unloading and action calling
     *
     * @return bool
     */
    public function dispatch() {
        if ($_SERVER['REQUEST_URI'][strlen($_SERVER['REQUEST_URI']) - 1] !== '/') {
            $_SERVER['REQUEST_URI'] .= '/'; //add end slash for safety (if missing)
        }

        //$_SERVER['REQUEST_URI'] = @str_replace( BASE ,'', $_SERVER['REQUEST_URI']);
        // We divide the request into 'module' and 'action' and save paramaters into $_PARAMS
        if ($_SERVER['REQUEST_URI'] != '/') {
            $_PARAMS = explode('/', $_SERVER['REQUEST_URI']);

            $moduleName = $_PARAMS[1]; //get module name
            $actionName = $_PARAMS[2]; //get action
            unset($_PARAMS[count($_PARAMS) - 1]); //delete last
            unset($_PARAMS[0]);
            unset($_PARAMS[1]);
            unset($_PARAMS[2]);
        } else {
            $_PARAMS = null;
        }

        if (empty($actionName)) {
            $actionName = 'index'; //use default index action
        }

        if (empty($moduleName)) {
            $moduleName = 'main'; //use default main module
        }
        /* if (isset($_PARAMS))

          {

          $_PARAMS = array_slice($_PARAMS, 3, -1);//delete action and module from array and pass only parameters

          } */
        return self :: redirect($moduleName, $actionName, $_PARAMS);
    }
}

PHP में ऑपरेटरों का एक सिंहावलोकन:

लॉजिकल ऑपरेटर्स:

  • $ a && $ b: सत्य अगर दोनों $ a और $ b सत्य हैं।
  • $ ए || $ बी: सही अगर या तो $ एक या $ बी सत्य है।
  • $ एक xor $ b: सत्य अगर या तो $ एक या $ बी सत्य है, लेकिन दोनों नहीं।
  • ! $ ए: सही अगर $ एक सत्य नहीं है।
  • $ ए और $ बी: सही अगर दोनों $ और $ बी सत्य हैं।
  • $ ए या $ बी: सही अगर कोई $ या $ बी सत्य है।

तुलना ऑपरेटर:

  • $ a == $ b: सही अगर $ j टाइपिंग के बाद $ b के बराबर है।
  • $ a === $ b: सही अगर $ एक $ बी के बराबर है, और वे एक ही प्रकार के हैं।
  • $ ए! = $ बी: सही अगर $ j टाइपिंग के बाद $ b के बराबर नहीं है।
  • $ a <> $ b: सही अगर $ j टाइपिंग के बाद $ b के बराबर नहीं है।
  • $ ए! == $ बी: सही अगर $ ए $ बी के बराबर नहीं है, या वे एक ही प्रकार के नहीं हैं।
  • $ a <$ b : सही अगर $ ए कड़ाई से $ बी से कम है।
  • $ ए> $ बी : सही अगर $ ए कड़ाई से $ बी से अधिक है।
  • $ a <= $ b : सही अगर $ एक $ बी से कम या बराबर है।
  • $ a> = $ b : सही अगर $ एक $ बी से अधिक या बराबर है।
  • $ a <=> $ b : शून्य से कम, बराबर, या शून्य से अधिक एक पूर्णांक क्रमशः $ बी से कम, बराबर या उससे अधिक है। PHP 7 के रूप में उपलब्ध है।
  • $ ए? $ बी: $ सी : अगर $ एक वापसी $ बी और $ सी ( टर्नरी ऑपरेटर ) वापस
  • $ एक ?? $ सी : $ ए के समान? $ ए: $ सी ( शून्य कोलेसिंग ऑपरेटर - PHP> = 7 की आवश्यकता है)

अंकगणितीय आपरेटर:

  • - $ ए : $ ए के विपरीत।
  • $ ए + $ बी : $ ए और $ बी का योग।
  • $ ए - $ बी : $ ए और $ बी का अंतर।
  • $ ए * $ बी : $ ए और $ बी का उत्पाद।
  • $ ए / $ बी : $ ए और $ बी का कोटिएंट।
  • $ एक% $ बी : $ बी के विभाजित $ के शेष।
  • $ एक ** $ बी : $ b'th पावर को $ एक बढ़ाने का परिणाम (PHP 5.6 में पेश किया गया)

बढ़ते / घटाने वाले ऑपरेटरों:

  • ++ $ ए : $ एक से बढ़ता है, फिर $ ए देता है।
  • $ ए ++ : $ एक देता है, फिर $ एक को बढ़ाता है।
  • - $ ए : एक करके $ एक घटाता है, फिर $ ए देता है।
  • $ a-- : $ एक देता है, फिर $ एक को कम करता है।

बिटवाई ऑपरेटर:

  • $ ए और $ बी : बिट्स जो $ ए और $ बी दोनों में सेट हैं सेट हैं।
  • $ ए | $ बी : $ एक या $ बी में सेट बिट्स सेट हैं।
  • $ a ^ $ b : बिट्स जो $ a या $ b में सेट हैं लेकिन दोनों सेट नहीं हैं।
  • ~ $ ए : बिट्स जो $ एक में सेट हैं सेट नहीं हैं, और इसके विपरीत।
  • $ a << $ b : बाईं ओर $ $ b चरणों के बिट्स को Shift करें (प्रत्येक चरण का अर्थ है "दो से गुणा करें")
  • $ ए >> $ बी : दाईं ओर $ $ बी चरणों के बिट्स को शिफ्ट करें (प्रत्येक चरण का मतलब है "दो से विभाजित करें")

स्ट्रिंग ऑपरेटर:

  • $ ए $ बी : $ ए और $ बी का संतोष।

ऐरे ऑपरेटर:

  • $ ए + $ बी : $ ए और $ बी का संघ।
  • $ a == $ b : सही अगर $ a और $ b में एक ही कुंजी / मान जोड़े हैं।
  • $ a === $ b : सही अगर $ ए और $ बी में एक ही कुंजी / वैल्यू जोड़े एक ही क्रम में और उसी प्रकार के होते हैं।
  • $ ए! = $ बी : सही अगर $ ए $ बी के बराबर नहीं है।
  • $ a <> $ b : सत्य अगर $ ए $ बी के बराबर नहीं है।
  • $ ए! == $ बी : सही अगर $ ए $ बी के समान नहीं है।

असाइनमेंट ऑपरेटर:

  • $ ए = $ बी : $ बी का मूल्य $ ए को सौंपा गया है
  • $ ए + = $ बी : $ ए = $ ए + $ बी के समान
  • $ ए - = $ बी : $ ए = $ ए - $ बी के समान
  • $ ए * = $ बी : $ ए = $ ए * $ बी के समान
  • $ ए / = $ बी : $ ए = $ ए / $ बी के समान
  • $ एक% = $ बी : $ = $ एक% $ बी के समान
  • $ एक ** = $ बी : $ = $ एक ** $ b के समान
  • $ ए। = $ बी : $ ए = $ ए के समान। $ ख
  • $ ए और = $ बी : $ एक = $ ए और $ बी के समान
  • $ ए | = $ बी : $ एक = $ ए के समान $ ख
  • $ a ^ = $ b : $ a = $ a ^ $ b के समान
  • $ a << = $ b : $ a = $ a << $ b के समान
  • $ ए >> = $ बी : $ एक = $ एक >> $ बी के समान

ध्यान दें

and ऑपरेटर और ऑपरेटर असाइनमेंट ऑपरेटर = तुलना में कम प्राथमिकता है।

इसका मतलब है कि $a = true and false; बराबर है ($a = true) and false

ज्यादातर मामलों में आप शायद && और || का उपयोग करना चाहेंगे , जो सी, जावा या जावास्क्रिप्ट जैसी भाषाओं से ज्ञात तरीके से व्यवहार करता है।





php performance reflection