দ্রুত কি: ইন_আরে বা আইসেট? [বন্ধ]


99

এই প্রশ্নটি কেবল আমার পক্ষে, কারণ আমি সর্বদা অনুকূলিত কোড লিখতে চাই যা সস্তা ধীর সার্ভারগুলিতে (বা প্রচুর ট্র্যাফিক সহ সার্ভার) চালাতে পারে write

আমি চারপাশে তাকিয়েছিলাম এবং আমি কোনও উত্তর খুঁজে পাইনি। আমি ভাবছিলাম যে আমার ক্ষেত্রে অ্যারের কীগুলি গুরুত্বপূর্ণ নয় (সিউডো কোড প্রাকৃতিকভাবে) এই বিষয়টি মাথায় রেখে এই দুটি উদাহরণের মধ্যে দ্রুততর কী?

<?php
$a = array();
while($new_val = 'get over 100k email addresses already lowercased'){
    if(!in_array($new_val, $a){
        $a[] = $new_val;
        //do other stuff
    }
}
?>

<?php
$a = array();
while($new_val = 'get over 100k email addresses already lowercased'){
    if(!isset($a[$new_val]){
        $a[$new_val] = true;
        //do other stuff
    }
}
?>

যেহেতু প্রশ্নের বিন্দুটি অ্যারের সংঘর্ষ নয়, আমি এটি যুক্ত করতে চাই যে আপনি যদি সন্নিবেশকারী সন্নিবেশগুলি সম্পর্কে ভীত হন তবে $a[$new_value]আপনি এটি ব্যবহার করতে পারেন $a[md5($new_value)]। এটি এখনও সংঘর্ষের কারণ হতে পারে, তবে কোনও ব্যবহারকারী প্রদত্ত ফাইল ( http://nikic.github.com/2011/12/28/Supercollider-a-PHP-array.html ) থেকে পড়া অবস্থায় একটি সম্ভাব্য ডস আক্রমণ থেকে দূরে সরে যাবে


4
আপনি যদি সর্বদা অপ্টিমাইজড কোডটি লেখার চেষ্টা করছেন, আপনি অবশ্যই কোনও প্রোফাইলার ব্যবহার করছেন তবে একবারে?
মারিও

61
আমি আবার খুলতে ভোট। প্রশ্নটি ভালভাবে গঠন করা হয়েছে এবং উত্তরগুলি তথ্য এবং তথ্যসূত্রগুলির সাথে সমর্থিত। একটি অণু- কার্যকরকরণের সময় এই ধরণের প্রশ্নগুলি গঠনমূলক
জেসন ম্যাকক্রিয়ারি

5
@ জেসনমিসক্রিরি দ্বিতীয়; শুধু একটা আরো.
জ্যাক

7
এটি বহু বছর পরে, তবে আমি এটিকে একটি মাইক্রো অপ্টিমাইজেশনও বিবেচনা করব না। বড় ডেটা সেটগুলির জন্য এটি এক টন পার্থক্য করতে পারে !!
রবার্ট

4
... এই প্রশ্নটি আমার কাছে "গঠনমূলক" মনে হচ্ছে। আমি আরেকটি পুনরায় খোলার প্রচারণা শুরু করব।
মিকম্যাকুসা

উত্তর:


120

এখনও পর্যন্ত উত্তর স্পট-অন হয়। issetএই ক্ষেত্রে ব্যবহার করা কারণ দ্রুত

  • এটি কীতে একটি ও (1) হ্যাশ অনুসন্ধান ব্যবহার করে যেখানে in_arrayএটি কোনও মিল খুঁজে না পাওয়া পর্যন্ত প্রতিটি মান অবশ্যই পরীক্ষা করে।
  • অপকোড হওয়ায় in_arrayবিল্ট-ইন ফাংশনটি কল করার চেয়ে এর কম ওভারহেড রয়েছে ।

মানগুলি (নীচের পরীক্ষায় 10,000) এর সাথে অ্যারে ব্যবহার করে এগুলি প্রদর্শিত হতে পারে, in_arrayআরও অনুসন্ধান করতে বাধ্য করা।

isset:    0.009623
in_array: 1.738441

এটি কিছু এলোমেলো মান পূরণ করে এবং মাঝে মাঝে অ্যারেতে উপস্থিত একটি মান খুঁজে বের করে জেসনের মানদণ্ডে গড়ে তোলে। সমস্ত এলোমেলো, তাই সতর্ক থাকুন যে সময়গুলি ওঠানামা করবে।

$a = array();
for ($i = 0; $i < 10000; ++$i) {
    $v = rand(1, 1000000);
    $a[$v] = $v;
}
echo "Size: ", count($a), PHP_EOL;

$start = microtime( true );

for ($i = 0; $i < 10000; ++$i) {
    isset($a[rand(1, 1000000)]);
}

$total_time = microtime( true ) - $start;
echo "Total time: ", number_format($total_time, 6), PHP_EOL;

$start = microtime( true );

for ($i = 0; $i < 10000; ++$i) {
    in_array(rand(1, 1000000), $a);
}

$total_time = microtime( true ) - $start;
echo "Total time: ", number_format($total_time, 6), PHP_EOL;

আমি হ্যাশগুলি সম্পর্কে জানি, তবে ভাবছি কেন ক্রিয়াকলাপকে গতিময় করা সম্ভব হলে অ্যারে মানগুলিতে কেন অনুরূপ কিছু করা হয় না, যদি অনুরূপ মানগুলি কেবলমাত্র মানটিতে অতিরিক্ত হ্যাশিং যুক্ত করে ব্যবহৃত হয় তবে এটি মেমরির গ্রহণও হ্রাস করবে .. সঠিক?
Fabrizio

4
@ ফ্যাবরিজিও - অ্যারের মানগুলি নকল করা যায় এবং নন-হ্যাশযোগ্য অবজেক্ট থাকতে পারে। কীগুলি অবশ্যই অনন্য হতে হবে এবং কেবল স্ট্রিং এবং পূর্ণসংখ্যার হতে পারে যা এগুলি সহজেই হ্যাশযোগ্য করে তোলে। আপনি যখন এক-এক-এক মানচিত্র তৈরি করতে পেরেছেন যা কী এবং মান উভয়কেই হ্যাশ করেছে, পিএইচপি-এর অ্যারেটি এভাবে কাজ করে না।
ডেভিড হার্কনেস

4
আপনি যদি নিশ্চিত হন যে আপনার অ্যারেতে স্বতন্ত্র মান রয়েছে তবে অন্য একটি বিকল্প রয়েছে - ফ্লিপ + ইসসেট
আরকাদিজ কুজেল

একটি উল্টাপাল্টী আইসেটটি লক্ষণীয় ইন_আরয়ের চেয়ে এই উদাহরণে আরও দ্রুত:: `` $ শুরু = মাইক্রোটাইম (সত্য); oo foo = অ্যারে_ফ্লিপ ($ এ); ($ i = 0; $ i <10000; ++ $ i) {আইসেট ($ ফু [র্যান্ড (1, 1000000)]) এর জন্য; ; $ টোটাল_টাইম = মাইক্রোটাইম (সত্য) - $ শুরু; প্রতিধ্বনি "মোট সময় (ফ্ল্যাপড এসসেট):", সংখ্যা_ ফর্ম্যাট ($ মোট_টাইম, 6), পিএইচপি_ইএল;
আন্দ্রে বাউমিয়ার

@ আন্ড্রেবাউমিয়ার যা দ্রুততর তা অ্যারের আকার এবং আপনি কতগুলি পরীক্ষা নেবেন তার উপর নির্ভর করবে। তিনটি পরীক্ষার জন্য দশ হাজার উপাদান অ্যারে উল্টানো সম্ভবত দক্ষ নয়।
ডেভিড হার্কনেস

43

কোনটি দ্রুত: isset()বনামin_array()

isset() দ্রুততর.

এটি সুস্পষ্ট হওয়া উচিত, isset()কেবলমাত্র একটি একক মান পরীক্ষা করে। যেখানে in_array()প্রতিটি অ্যারের মান পরীক্ষা করে পুরো অ্যারেতে পুনরাবৃত্তি হবে।

রুক্ষ বেঞ্চমার্কিং ব্যবহার করা বেশ সহজ microtime()

ফলাফল:

Total time isset():    0.002857
Total time in_array(): 0.017103

দ্রষ্টব্য: ফলাফল অস্তিত্বহীন বা না থাকলে নির্বিশেষে একই রকম ছিল।

কোড:

<?php
$a = array();
$start = microtime( true );

for ($i = 0; $i < 10000; ++$i) {
    isset($a['key']);
}

$total_time = microtime( true ) - $start;
echo "Total time: ", number_format($total_time, 6), PHP_EOL;

$start = microtime( true );

for ($i = 0; $i < 10000; ++$i) {
    in_array('key', $a);
}

$total_time = microtime( true ) - $start;
echo "Total time: ", number_format($total_time, 6), PHP_EOL;

exit;

অতিরিক্ত সম্পদ

আমি আপনাকে দেখার জন্য উত্সাহিত করব:


সুন্দর সমাধান। আমি অবাক হয়েছি যে আরও বেশি লোক তাদের ফাংশন / কোড বেশি microtime()বা অন্যান্য সরঞ্জাম ব্যবহার করে বিভক্ত হয়ে যায় না । অবিশ্বাস্যভাবে মূল্যবান।
নিখর

4
একই কীটির জন্য একটি খালি অ্যারে অনুসন্ধান কেবল বিল্ট-ইন in_arrayব্যবহার করে ফাংশন কল করার ওভারহেডটি হাইলাইট করে isset। এটি এ্যান্ডের সাথে আরও ভাল হতে পারে যা এলোমেলো কীগুলির একটি গুচ্ছ থাকে এবং মাঝে মাঝে একটি বিদ্যমান কী / মান সন্ধান করে।
ডেভিড হার্কনেস

আমি বেশ খানিকটা বেঞ্চমার্ক এবং মাইক্রোটাইম ব্যবহার করি, তবে আমি এটিও উপলব্ধি করেছিলাম, যখন আমি পরীক্ষা করছিলাম whileএবং foreachপ্রতিটি রিফ্রেশে আমি আলাদা "বিজয়ী" পাচ্ছিলাম। এটি সর্বদা অনেকগুলি সার্ভারের ভেরিয়েবলের উপর নির্ভর করে এবং সেরাটি হ'ল বিভিন্ন সময় খুব বড় সংখ্যক বার পুনরাবৃত্তি করা এবং যেটি প্রায়শই জয়ী হয় তা পেতে পারেন, বা ব্যাকগ্রাউন্ডে কী ঘটছে তা জানেন এবং জানেন যে এটি চূড়ান্ত বিজয়ী হবে know যাই হোক না কেন
Fabrizio

@ ডেভিড হার্কনেস, আপনি ইতিমধ্যে আমার উত্তরটি উত্তোলন করেছেন। আপনি যদি আরও চান তবে আমার কাঁধে দাঁড়িয়ে আপনার নিজের উত্তর পোস্ট করুন। :) তবুও, যদি ফাংশন ওভারহেড ইতিমধ্যে তুলনামূলকভাবে বেশি ব্যয়বহুল হয় তবে isset()আপনি কী ভাবেন যে এটি আরও বড় অ্যারে পাস করা দ্রুততর করবে ?
জেসন ম্যাকক্রিয়ারি


19

ব্যবহার isset()দ্রুততর অনুসন্ধানের সুবিধা নেয় কারণ এটি হ্যাশ টেবিল ব্যবহার করে, O(n)অনুসন্ধানগুলির প্রয়োজনীয়তা এড়িয়ে চলে ।

অনুরূপভাবে হ্যাশ কীগুলির বালতি নির্ধারণ করতে প্রথমে কীটি হ্যাশ করা হয় ডিজেবি হ্যাশ ফাংশনটি ব্যবহার করে O(1)। সঠিক কীটি না পাওয়া পর্যন্ত বালতিটি পুনরাবৃত্তভাবে অনুসন্ধান করা হয় O(n)

কোনও ইচ্ছাকৃত হ্যাশের সংঘর্ষ বাদে এই পদ্ধতির তুলনায় অনেক ভাল পারফরম্যান্স পাওয়া যায় in_array()

মনে রাখবেন যে isset()আপনি যেভাবে দেখিয়েছেন সেভাবে ব্যবহার করার সময়, চূড়ান্ত মানগুলি অন্য ফাংশনে পাস array_keys()করার জন্য একটি নতুন অ্যারে তৈরি করার প্রয়োজন । কী এবং মান উভয়ই ডেটা সঞ্চয় করে একটি মেমরি সমঝোতা করা যেতে পারে।

হালনাগাদ

আপনার কোড ডিজাইনের সিদ্ধান্তগুলি রানটাইম কর্মক্ষমতাকে কীভাবে প্রভাবিত করে তা দেখার একটি ভাল উপায়, আপনি আপনার স্ক্রিপ্টের সংকলিত সংস্করণটি পরীক্ষা করতে পারেন :

echo isset($arr[123])

compiled vars:  !0 = $arr
line     # *  op                           fetch      ext  return  operands
-----------------------------------------------------------------------------
   1     0  >   ZEND_ISSET_ISEMPTY_DIM_OBJ              2000000  ~0      !0, 123
         1      ECHO                                                 ~0
         2    > RETURN                                               null

echo in_array(123, $arr)

compiled vars:  !0 = $arr
line     # *  op                           fetch      ext  return  operands
-----------------------------------------------------------------------------
   1     0  >   SEND_VAL                                             123
         1      SEND_VAR                                             !0
         2      DO_FCALL                                 2  $0      'in_array'
         3      ECHO                                                 $0
         4    > RETURN                                               null

কেবল in_array()অপেক্ষাকৃত অদক্ষ O(n)অনুসন্ধানই ব্যবহার করে না , এটি ফাংশন ( DO_FCALL) হিসাবেও ডাকা প্রয়োজন যেখানে এর জন্য isset()একটি একক অপকোড ( ZEND_ISSET_ISEMPTY_DIM_OBJ) ব্যবহার করা হয়।


7

দ্বিতীয়টি দ্রুততর হবে, কারণ এটি কেবলমাত্র নির্দিষ্ট নির্দিষ্ট অ্যারে কীটির সন্ধান করছে এবং এটি না পাওয়া পর্যন্ত পুরো অ্যারেতে পুনরাবৃত্তি করার প্রয়োজন নেই (এটি পাওয়া না গেলে প্রতিটি অ্যারের উপাদানটি দেখবে)


তবে এটি বিশ্বব্যাপী স্কোয়ারে অনুসন্ধান করা ভেরির অবস্থানের উপরও নির্ভর করে
এল ডুড

@ EL2002, আপনি দয়া করে বিবৃতিটি বিস্তারিত বলতে পারেন?
Fabrizio

4
মাইক, isset()এটি খুঁজে না পাওয়া সত্ত্বেও পুরো অ্যারের দিকে তাকিয়ে থাকবে ?
Fabrizio

4
@ ফ্যাবরিজিও না, এটি পুনরাবৃত্তি করার দরকার নেই। অভ্যন্তরীণভাবে (সি তে) পিএইচপি অ্যারে কেবল একটি হ্যাশ টেবিল। একটি একক সূচক মানের সন্ধানের জন্য, সি কেবল সেই মানটির একটি হ্যাশ তৈরি করে এবং মেমোরিতে তার নির্ধারিত অবস্থান সন্ধান করে। সেখানে একটি মান আছে বা হয় না।
মাইক ব্রেন্ট

4
@ ফ্যাবরিজিও এই নিবন্ধটি পিএইচপি দ্বারা সিটিতে অভ্যন্তরীণভাবে কীভাবে উপস্থাপন করা হয় তার একটি ভাল ওভারভিউ সরবরাহ করে। nikic.github.com/2012/03/28/…
মাইক ব্রেন্ট
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.