2017-07-11 7 views
8

मेरा एप्लिकेशन एमबी_ स्ट्रिंग फ़ंक्शंस का व्यापक उपयोग करता है और php 7 पर स्विच करता है जिसके परिणामस्वरूप कुल धीमी गति होती है। मैंने mb_ स्ट्रिंग फ़ंक्शंस में समस्याओं को ट्रैक किया।PHP 7 एमबी_ (मल्टीबाइट) फ़ंक्शंस ~ 60% की तुलना में ~ 60% धीमी हैं (विंडोज़ केवल समस्या)

$time = microtime(); 
$time = explode(' ', $time); 
$start = $time[1] + $time[0]; 
$startms = $time[0]; 
    for ($i=0; $i<100000; $i++) { 
     $a = mb_strlen("fdsfdssdfoifjosdifjosdifjosdij:ά", "UTF-8"); 
    } 
$time = microtime(); 
$time = explode(' ', $time); 
$finish = $time[1] + $time[0]; 
$finishms = $time[0]; 
$total_time = round(($finish - $start), 4); 
echo "mb_strlen: " . $total_time*1000 ." milliseconds<br/>"; 

$time = microtime(); 
$time = explode(' ', $time); 
$start = $time[1] + $time[0]; 
$startms = $time[0]; 
    for ($i=0; $i<100000; $i++) { 
     $a = mb_stripos("fdsfdssdfoifjosdifjosdifjosdij:ά", "α", 0, "UTF-8"); 
    } 
$time = microtime(); 
$time = explode(' ', $time); 
$finish = $time[1] + $time[0]; 
$finishms = $time[0]; 
$total_time = round(($finish - $start), 4); 
echo "mb_stripos: " . $total_time*1000 ." milliseconds<br/>"; 


$time = microtime(); 
$time = explode(' ', $time); 
$start = $time[1] + $time[0]; 
$startms = $time[0]; 
    for ($i=0; $i<100000; $i++) { 
     $a = mb_substr("fdsfdssdfoifjosdifjosdifjosdij:ά", $i, 1, "UTF-8"); 
    } 
$time = microtime(); 
$time = explode(' ', $time); 
$finish = $time[1] + $time[0]; 
$finishms = $time[0]; 
$total_time = round(($finish - $start), 4); 
echo "mb_substr: " . $total_time*1000 ." milliseconds<br/>"; 

मंच विंडोज 7 64 बिट है, IIS 7.5:

php 5.3.28 
mb_strlen: 250 milliseconds 
mb_stripos: 3078.1 milliseconds 
mb_substr: 281.3 milliseconds 

php 7.1.1 
mb_strlen: 406.3 milliseconds 
mb_stripos: 4796.9 milliseconds 
mb_substr: 421.9 milliseconds 

मैं अगर मेरे सेट अप गलत या कुछ और है पता नहीं है, लेकिन समझ से बाहर लगता है यहाँ बेंचमार्क कोड और परिणाम हैं कि multibyte कार्यों धीमी होनी चाहिए। इस बात को हल करने के लिए क्यों और क्या करना है इसके बारे में कोई विचार? पहले ही, आपका बहुत धन्यवाद।

संपादित करें: apokryfos की टिप्पणी से पता चलता है, यह एक विंडोज़ केवल समस्या हो सकती है।

+0

क्षमा करें, मैं सिर्फ यह http://sandbox.onlinephpfunctions.com/code/401f138baf7c4110f1370f8e597bba5610dd0a47 नहीं दिख रहा है – apokryfos

+0

@apokryfos मैं नहीं जानता कि क्या ओएस:

इस कोड (छोटा) है आपके द्वारा प्रदान किए गए टेस्ट लिंक को चलाता है, शायद यह php – MIrrorMirror

+2

के विंडोज संस्करण के साथ एक मुद्दा है, बस पठनीयता के लिए: 'माइक्रोटाइम' एक बूलियन तर्क लेता है जो इसे पहले से ही एक फ्लोट लौटाता है - 'विस्फोट' करने की कोई आवश्यकता नहीं है - इसके बारे में सोचना: यह पूरी समस्या हो सकती है, '$ time = विस्फोट ('', $ time) क्या है; $ start = $ time [1] + $ time [0]; 'प्रतिनिधित्व करना चाहिए? आप बस सेकंड टाइम में वर्तमान टाइमस्टैम्प का msec हिस्सा जोड़ रहे हैं? – ccKep

उत्तर

3

मैं पुष्टि कर सकता है कि अपने परिणाम विंडोज पर प्रतिलिपि प्रस्तुत करने योग्य है 7. कुछ प्रयोगों के बाद, मुझे एक त्वरित समाधान मिला कि आईएमओ का प्रभाव भी नहीं होना चाहिए।

जैसा कि आप mb_strlen() फ़ंक्शन हस्ताक्षर से देख सकते हैं, यदि आप एन्कोडिंग पैरामीटर को छोड़ देते हैं तो यह आंतरिक एन्कोडिंग का उपयोग करेगा। यह आपके द्वारा उपयोग किए जाने वाले अन्य कार्यों पर भी लागू होता है।

mixed mb_strlen (string $str [, string $encoding = mb_internal_encoding() ]) 

क्या मैं अजीब पाया अगर आप mb_internal_encoding("UTF-8") फोन करके UTF-8 में आंतरिक एन्कोडिंग सेट और एन्कोडिंग पैरामीटर छोड़ देते है, कार्यों तेज़ हो गया है।

पीएचपी 5.5 परिणाम:

5.5.12 

with encoding parameter: 
- mb_strlen: 172 ms, result: 5 
- mb_substr: 218 ms, result: う 
- mb_strpos: 218 ms, result: 3 
- mb_stripos: 1,669 ms, result: 3 
- mb_strrpos: 234 ms, result: 3 
- mb_strripos: 1,685 ms, result: 3 

with internal encoding: 
- mb_strlen: 47 ms, result: 5 
- mb_substr: 78 ms, result: う 
- mb_strpos: 62 ms, result: 3 
- mb_stripos: 1,669 ms, result: 3 
- mb_strrpos: 94 ms, result: 3 
- mb_strripos: 1,669 ms, result: 3 

पीएचपी 7.0 परिणाम:

7.0.12 

with encoding parameter: 
- mb_strlen: 640 ms, result: 5 
- mb_substr: 702 ms, result: う 
- mb_strpos: 686 ms, result: 3 
- mb_stripos: 7,067 ms, result: 3 
- mb_strrpos: 749 ms, result: 3 
- mb_strripos: 7,130 ms, result: 3 

with internal encoding: 
- mb_strlen: 31 ms, result: 5 
- mb_substr: 31 ms, result: う 
- mb_strpos: 47 ms, result: 3 
- mb_stripos: 7,270 ms, result: 3 
- mb_strrpos: 62 ms, result: 3 
- mb_strripos: 7,116 ms, result: 3 

दुर्भाग्य से, इस त्वरित समाधान नहीं सही mb_stripos() के रूप में और mb_strripos() प्रभावित हो सकते हैं नहीं है। वे अभी भी धीमे हैं।

echo PHP_VERSION."\n"; 
echo "\nwith encoding parameter:\n"; 

$t = microtime(true)*1000; 
for($i=0; $i<100000; $i++){ 
    $n = mb_strlen("あえいおう","UTF-8"); 
} 
$t = microtime(true)*1000-$t; 
echo "- mb_strlen: ".number_format($t)." ms, result: {$n}\n"; 

$t = microtime(true)*1000; 
for($i=0; $i<100000; $i++){ 
    $n = mb_substr("あえいおう",-1,1,"UTF-8"); 
} 
$t = microtime(true)*1000-$t; 
echo "- mb_substr: ".number_format($t)." ms, result: {$n}\n"; 

//set internal encoding 
//and omit encoding parameter 

mb_internal_encoding("UTF-8"); 
echo "\nwith internal encoding:\n"; 

$t = microtime(true)*1000; 
for($i=0; $i<100000; $i++){ 
    $n = mb_strlen("あえいおう"); 
} 
$t = microtime(true)*1000-$t; 
echo "- mb_strlen: ".number_format($t)." ms, result: {$n}\n"; 

$t = microtime(true)*1000; 
for($i=0; $i<100000; $i++){ 
    $n = mb_substr("あえいおう",-1,1); 
} 
$t = microtime(true)*1000-$t; 
echo "- mb_substr: ".number_format($t)." ms, result: {$n}\n"; 
+0

वाह यह अजीब – hanshenrik

+0

कोई है कृपया किसी बग रिपोर्ट को दर्ज करें, यह एक बग – hanshenrik

+0

@ हंसेनरिक ने इसके लिए https: // bugs भी दर्ज किया है। php.net/bug.php?id=74935 – MIrrorMirror

3

यह "प्रदर्शन प्रतिगमन" बग की तरह लगता है। शायद एक बग्रेपोर्ट दर्ज करना चाहिए, इसलिए php core devs इसे देख सकते हैं, bugs.php.net

इस बीच, मैं देखता हूं कि आपके स्निपेट में आप विशेष रूप से यूटीएफ -8 का उपयोग कर रहे हैं। जब तक आप विशेष रूप से यूटीएफ -8 का उपयोग कर रहे हैं, तो आप preg_ का उपयोग करके इसे गति देने में सक्षम हो सकते हैं, जो केवल 1 प्रकार के यूनिकोड वर्णमाला का समर्थन करता है: UTF-8

function _mb_strlen(string $str, string $encoding = 'UTF-8'): int { 
    assert ($encoding === 'UTF-8'); 
    preg_match ('/.$/u', $str, $matches, PREG_OFFSET_CAPTURE); 
    return empty ($matches) ? 0 : ($matches [0] [1]) + 1; 
} 
function _mb_stripos(string $haystack, string $needle, int $offset = 0, string $encoding = 'UTF-8') { 
    assert ($encoding === 'UTF-8'); 
    if ($offset !== 0) { 
     throw new LogicException ('NOT IMPLEMENTED'); 
    } 
    preg_match ('/' . preg_quote ($needle) . '/ui', $haystack, $matches, PREG_OFFSET_CAPTURE); 
    return empty ($matches) ? false : $matches [0] [1]; 
} 
function _mb_substr(string $str, int $start, int $length = NULL, string $encoding = 'UTF-8'): string { 
    assert ($encoding === 'UTF-8'); 
    if ($start < 0) { 
     throw new LogicException ('NOT IMPLEMENTED'); 
    } elseif ($start > 0) { 
     $rex = '/.{' . $start . '}(.{0,'; 
    } else { 
     $rex = '/(.{0,'; 
    } 
    if ($length !== NULL) { 
     $rex .= $length; 
    } 
    $rex .= '})/u'; 
    preg_match ($rex, $str, $matches); 
    // var_dump ($rex, $matches); 
    return empty ($matches) ? '' : $matches [1]; 
} 

यहाँ पर डेबियन 9 linux php 7.0 पर 100,000 पुनरावृत्तियों पर अपना बेंचमार्क परिणाम है (कर्नेल 4.9): यहाँ मेरी प्रयास है

mb_strlen धीमी है, के बारे में 60ms से 100 एमएस

mb_stripos से मिला बहुत तेजी से 75ms

mb_substr बहुत धीमी है, के लिए 1400ms के बारे में से 47 के बारे में एमएस से लगभग 800 एमएस

    करने के लिए
  • लेकिन मैं तुम्हें फिर से चलाने के खिड़कियों पर इन परीक्षणों, जैसा कि आप ने कहा कि आपको लगता है कि यह एक windows-विशेष मुद्दा

यह भी ध्यान रखें हो सकता है, इन कार्यों को पूरा करने की सुविधा नहीं कर रहे हैं, जैसा कि आप LogicException के से देख सकते हैं सुझाव है वे फेंकते है।

भी ध्यान रखें कि preg_ में एक सीमा के कारण, मैं

for($i = 0; $i < 65000; $i ++) { 
    $a = mb_substr ("fdsfdssdfoifjosdifjosdifjosdij:ά", $i, 1, "UTF-8"); 
} 

में 65000 पुनरावृत्तियों में mb_substr सीमित रखने के लिए, क्योंकि अगर आप 65,000 से अधिक वर्ण लंबा एक स्ट्रिंग देखने के लिए preg पूछना, यह एक दे देंगे था त्रुटि ...

भी ध्यान रखें कि आपके बेंचमार्क कोड इस

$time = microtime(); 
$time = explode(' ', $time); 
$start = $time[1] + $time[0]; 
$startms = $time[0]; 
    for ($i=0; $i<100000; $i++) { 
     $a = mb_strlen("fdsfdssdfoifjosdifjosdifjosdij:ά", "UTF-8"); 
    } 
$time = microtime(); 
$time = explode(' ', $time); 
$finish = $time[1] + $time[0]; 
$finishms = $time[0]; 
$total_time = round(($finish - $start), 4); 
echo "mb_strlen: " . $total_time*1000 ." milliseconds<br/>"; 

बस जो की तरह कुछ आउटपुट

$starttime=microtime(true); 
    for ($i=0; $i<100000; $i++) { 
     $a = mb_strlen("fdsfdssdfoifjosdifjosdifjosdij:ά", "UTF-8"); 
    } 
$endtime=microtime(true); 
echo "mb_strlen: " . number_format(($endtime-$starttime),3) ." seconds<br/>"; 

साथ बदला जा सकता, बहुत आसान बनाया जा सकता है के सभी: mb_strlen: 0.085 seconds (जिसके बारे में मतलब है 85 मिलीसेकंड)

या

echo "mb_strlen: " . number_format(($endtime - $starttime) * 1000),2) . " milliseconds<br/>"; 

(और मैं एक जंगली अनुमान ले जा सकते हैं यह realloc() प्रदर्शन, जिसमें linux stomps खिड़कियों के साथ कुछ करने के लिए है, लेकिन मैं कोई सबूत नहीं मिला है)

+0

आपके उत्तर के लिए धन्यवाद। ऑप्टिमाइज़ेशन कोड को मापने के समय के लिए सिर्फ एक टिप्पणी: इसका कारण यह है कि आपके जैसा और अन्य सुझाव दिया गया है, यह है कि यह टी> 1sec (नकारात्मक मान आदि दिखाता है) – MIrrorMirror

+1

ओह के लिए टूट जाता है, आप number_format() :) का उपयोग कर सकते हैं :) (मैं अब फोन पर हूं इसलिए मैं इसे ठीक नहीं करूँगा, लेकिन जब मैं कंप्यूटर पर वापस आऊंगा, तो मैं) – hanshenrik

+1

@MIrrorMirror ने इसे num_format ^^ के साथ तय किया है (और यदि आप नहीं करते हैं संख्या_फॉर्मैट के अन्य स्वरूपण संचालन चाहते हैं, बस इसे अंत में 2 खालीस्ट्रिंग तर्क दें) – hanshenrik

संबंधित मुद्दे