নিম্নলিখিত দুটি লুপের মধ্যে পারফরম্যান্সের পার্থক্য কী?
for (Object o: objectArrayList) {
o.DoSomething();
}
এবং
for (int i=0; i<objectArrayList.size(); i++) {
objectArrayList.get(i).DoSomething();
}
নিম্নলিখিত দুটি লুপের মধ্যে পারফরম্যান্সের পার্থক্য কী?
for (Object o: objectArrayList) {
o.DoSomething();
}
এবং
for (int i=0; i<objectArrayList.size(); i++) {
objectArrayList.get(i).DoSomething();
}
উত্তর:
জোশুয়া ব্লচের কার্যকর জাভাতে আইটেম 46 থেকে :
রিলিজ ১.০ এ প্রবর্তিত প্রতিটি লুপটি বিশৃঙ্খলা থেকে মুক্তি এবং পুনরুক্তি বা সূচক ভেরিয়েবল সম্পূর্ণরূপে গোপন করে ত্রুটির সুযোগ পেয়ে যায়। ফলস্বরূপ আইডিয়োম সংগ্রহ এবং অ্যারেগুলিতে সমানভাবে প্রযোজ্য:
// The preferred idiom for iterating over collections and arrays for (Element e : elements) { doSomething(e); }
আপনি যখন কোলন (:) দেখেন, তখন এটি "ভিতরে" হিসাবে পড়ুন। সুতরাং, উপরের লুপটি "প্রতিটি উপাদান এবং উপাদানগুলির জন্য" হিসাবে পড়ে। মনে রাখবেন যে প্রতিটি লুপ ব্যবহার করার জন্য, এমনকি অ্যারেগুলির জন্য কোনও পারফরম্যান্স পেনাল্টি নেই। প্রকৃতপক্ষে, এটি কিছু পরিস্থিতিতে লুপের জন্য একটি সাধারণের তুলনায় সামান্য পারফরম্যান্স সুবিধা দিতে পারে কারণ এটি অ্যারে সূচকটির সীমাটি কেবল একবারই গণনা করে। আপনি হাত দ্বারা এটি করতে পারবেন (আইটেম 45), প্রোগ্রামাররা সর্বদা এটি করে না।
এই সমস্ত লুপগুলি ঠিক একই কাজ করে, আমি আমার দুটি সেন্টে ফেলে দেওয়ার আগে এগুলি প্রদর্শন করতে চাই।
প্রথমত, তালিকার মাধ্যমে লুপিংয়ের সর্বোত্তম উপায়:
for (int i=0; i < strings.size(); i++) { /* do something using strings.get(i) */ }
দ্বিতীয়ত, পছন্দসই উপায়টি যেহেতু এটির ত্রুটি কম রয়েছে (আপনি কতবার "উফগুলি করেছেন, লুপগুলির মধ্যে এই লুপগুলিতে i এবং j ভেরিয়েবলগুলি মিশিয়েছেন?)"।
for (String s : strings) { /* do something using s */ }
তৃতীয়ত, লুপের জন্য মাইক্রো-অনুকূলিতকরণ:
int size = strings.size();
for (int i = -1; ++i < size;) { /* do something using strings.get(i) */ }
এখন আসল দুটি সেন্ট: আমি যখন এগুলি পরীক্ষা করছিলাম, তৃতীয়টি তখন মিলি সেকেন্ডগুলি গণনা করার সময় দ্রুততম ছিল যখন এটি একটি সাধারণ ক্রিয়াকলাপের সাথে প্রতিটি ধরণের লুপের জন্য কয়েক মিলিয়ন বার বার বার বলেছিল - এটি জাভা 5 ব্যবহার করছিল উইন্ডোতে jre1.6u10 এর সাথে যদি কারও আগ্রহ থাকে।
যদিও এটি অন্তত তৃতীয়টি দ্রুততম বলে মনে হচ্ছে, আপনার সত্যই নিজেকে জিজ্ঞাসা করা উচিত যে আপনি নিজের লুপিং কোডের যে কোনও জায়গায় এই পীফোল অপ্টিমাইজেশানটি বাস্তবায়নের ঝুঁকি নিতে চান যেহেতু আমি যা দেখেছি, আসল লুপিং ইজেন ' টি সাধারণত যে কোনও বাস্তব প্রোগ্রামের সবচেয়ে বেশি সময় ব্যয়কারী অংশ (বা সম্ভবত আমি কেবলমাত্র ভুল ক্ষেত্রে কাজ করছি, কে জানে)। এবং আমি জাভা -এর জন্য প্রতিটি লুপের অজুহাতে উল্লেখ করেছি (কিছু এটি আইট্রেটার লুপ হিসাবে এবং অন্যদেরকে ইন- লুপ হিসাবে উল্লেখ করে ) এটি ব্যবহার করার সময় আপনি সেই নির্দিষ্ট বোকা বাগটি আঘাত হানার সম্ভাবনা কম। এবং কীভাবে এটি এমনকি অন্যান্যগুলির চেয়েও দ্রুত হতে পারে তা বিতর্ক করার আগে মনে রাখবেন যে জাভাক বাইটোকোডটি মোটেও অনুকূলিত করে না (ভাল, প্রায় কোনওভাবেই), এটি কেবল এটি সংকলন করে।
আপনি যদি মাইক্রো অপ্টিমাইজেশনের মধ্যে থাকেন তবে এবং / অথবা আপনার সফ্টওয়্যার প্রচুর পুনরাবৃত্ত লুপ ব্যবহার করে এবং এরপরে আপনি তৃতীয় লুপের প্রকারে আগ্রহী হতে পারেন। আপনার সফটওয়্যারটি আপনার এই বিজোড়, মাইক্রো-অনুকূলিতকরণের জন্য লুপগুলি পরিবর্তন করার আগে এবং পরে উভয়ই ভাল করে নিজের সফটওয়্যারটি বেনমার্ক করে মনে রাখবেন।
get(int)
, অন্যটি ব্যবহার করে Iterator
। এটি একটি এন বার করায় যেহেতু LinkedList
এর পারফরম্যান্সটি for(int i=0;i<strings.size();i++) { /* do something using strings.get(i) */ }
আরও খারাপ কোথায় তা বিবেচনা করুন get(int)
।
প্রতিটি লুপের জন্য সাধারণত পছন্দ করা উচিত। আপনি যে তালিকা প্রয়োগ করছেন সেটি এলোমেলো অ্যাক্সেস সমর্থন না করে যদি "পান" পদ্ধতির ধীর গতি হতে পারে। উদাহরণস্বরূপ, যদি কোনও লিংকডলিস্ট ব্যবহার করা হয়, তবে আপনাকে ট্র্যাভারসাল ব্যয় করতে হবে, তবে প্রতিটি ক্ষেত্রে পদ্ধতির ক্ষেত্রে একটি পুনরুক্তি ব্যবহার করা হয় যা তালিকায় তার অবস্থানের উপর নজর রাখে। প্রতিটি লুপের সংক্ষিপ্তসার সম্পর্কে আরও তথ্য ।
আমার মনে হয় নিবন্ধটি এখানে রয়েছে: নতুন অবস্থান
এখানে প্রদর্শিত লিঙ্কটি মারা গিয়েছিল।
ঠিক আছে, পারফরম্যান্সের প্রভাবটি বেশিরভাগ ক্ষেত্রে তুচ্ছ, তবে শূন্য নয়। আপনি যদি RandomAccess
ইন্টারফেসের জাভাক ডকটি দেখুন :
থাম্বের নিয়ম হিসাবে, তালিকার প্রয়োগের সাথে এই ইন্টারফেসটি প্রয়োগ করা উচিত যদি শ্রেণীর সাধারণ উদাহরণগুলির জন্য, এই লুপটি:
for (int i=0, n=list.size(); i < n; i++) list.get(i);
এই লুপের চেয়ে দ্রুত চলে:
for (Iterator i=list.iterator(); i.hasNext();) i.next();
এবং প্রতিটি লুপটি পুনরাবৃত্তকারী সহ সংস্করণ ব্যবহার করছে, ArrayList
উদাহরণস্বরূপ, প্রতিটি লুপটি দ্রুততম হয় না।
দুর্ভাগ্যক্রমে একটি পার্থক্য রয়েছে বলে মনে হচ্ছে।
আপনি যদি উভয় ধরণের লুপের জন্য জেনারেটেড বাইটস কোডটি দেখেন তবে সেগুলি ভিন্ন।
এখানে Log4j উত্স কোড থেকে একটি উদাহরণ দেওয়া আছে।
/ লগ ৪ জ- এপি / এসআরসি / মেইন / জাভা / অর্গ /পাছে / ব্লগিং / লোগোজেজে / মার্কারম্যানেজার.জভাতে আমাদের লোগোজেজার্কার নামে একটি স্ট্যাটিক অভ্যন্তরীণ শ্রেণি রয়েছে যা সংজ্ঞায়িত করে:
/*
* Called from add while synchronized.
*/
private static boolean contains(final Marker parent, final Marker... localParents) {
//noinspection ForLoopReplaceableByForEach
for (final Marker marker : localParents) {
if (marker == parent) {
return true;
}
}
return false;
}
স্ট্যান্ডার্ড লুপ সহ:
private static boolean contains(org.apache.logging.log4j.Marker, org.apache.logging.log4j.Marker...);
Code:
0: iconst_0
1: istore_2
2: aload_1
3: arraylength
4: istore_3
5: iload_2
6: iload_3
7: if_icmpge 29
10: aload_1
11: iload_2
12: aaload
13: astore 4
15: aload 4
17: aload_0
18: if_acmpne 23
21: iconst_1
22: ireturn
23: iinc 2, 1
26: goto 5
29: iconst_0
30: ireturn
প্রত্যেকের জন্য:
private static boolean contains(org.apache.logging.log4j.Marker, org.apache.logging.log4j.Marker...);
Code:
0: aload_1
1: astore_2
2: aload_2
3: arraylength
4: istore_3
5: iconst_0
6: istore 4
8: iload 4
10: iload_3
11: if_icmpge 34
14: aload_2
15: iload 4
17: aaload
18: astore 5
20: aload 5
22: aload_0
23: if_acmpne 28
26: iconst_1
27: ireturn
28: iinc 4, 1
31: goto 8
34: iconst_0
35: ireturn
ওরাকল দিয়ে কী হবে?
আমি জাভা 7 এবং 8 এর সাথে উইন্ডোজ 7 এ চেষ্টা করেছি।
ইন্ডেক্সের পরিবর্তে পুনরুক্তি ব্যবহার করা ভাল। এর কারণ কারণ ইডিটর সম্ভবত তালিকা প্রয়োগের জন্য অনুকূলিত করা হয় যখন সূচকযুক্ত (কলিং গেট) নাও থাকতে পারে। উদাহরণস্বরূপ লিংকডলিস্ট একটি তালিকা তবে এর উপাদানগুলির মাধ্যমে সূচকগুলি পুনরুক্তি ব্যবহার করে পুনরাবৃত্তির চেয়ে ধীর হবে।
ভবিষ্যদ্বাণী আপনার কোডটির উদ্দেশ্যকে আরও পরিষ্কার করে তোলে এবং এটি সাধারণত খুব সামান্য গতির উন্নতির চেয়ে বেশি পছন্দ হয় - যদি থাকে তবে।
আমি যখনই একটি ইনডেক্সযুক্ত লুপ দেখি তখন আমার যা মনে হয় তা নিশ্চিত হয় তা নিশ্চিত করার জন্য আমাকে আরও কিছুক্ষণ পার্স করতে হবে উদাহরণস্বরূপ এটি শূন্য থেকে শুরু হয়, এটি কি শেষ পয়েন্টটি অন্তর্ভুক্ত করে বা বাদ দেয় না?
আমার বেশিরভাগ সময় কোড পড়ার জন্য ব্যয় হয়েছে বলে মনে হয় (যা আমি লিখেছি বা অন্য কেউ লিখেছেন) এবং পরিচ্ছন্নতা প্রায় সবসময় পারফরম্যান্সের চেয়ে গুরুত্বপূর্ণ। আজকাল এর কার্য সম্পাদন খারিজ করা সহজ কারণ হটস্পট এমন আশ্চর্যজনক কাজ করে।
নিম্নলিখিত কোড:
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;
interface Function<T> {
long perform(T parameter, long x);
}
class MyArray<T> {
T[] array;
long x;
public MyArray(int size, Class<T> type, long x) {
array = (T[]) Array.newInstance(type, size);
this.x = x;
}
public void forEach(Function<T> function) {
for (T element : array) {
x = function.perform(element, x);
}
}
}
class Compute {
int factor;
final long constant;
public Compute(int factor, long constant) {
this.factor = factor;
this.constant = constant;
}
public long compute(long parameter, long x) {
return x * factor + parameter + constant;
}
}
public class Main {
public static void main(String[] args) {
List<Long> numbers = new ArrayList<Long>(50000000);
for (int i = 0; i < 50000000; i++) {
numbers.add(i * i + 5L);
}
long x = 234553523525L;
long time = System.currentTimeMillis();
for (int i = 0; i < numbers.size(); i++) {
x += x * 7 + numbers.get(i) + 3;
}
System.out.println(System.currentTimeMillis() - time);
System.out.println(x);
x = 0;
time = System.currentTimeMillis();
for (long i : numbers) {
x += x * 7 + i + 3;
}
System.out.println(System.currentTimeMillis() - time);
System.out.println(x);
x = 0;
numbers = null;
MyArray<Long> myArray = new MyArray<Long>(50000000, Long.class, 234553523525L);
for (int i = 0; i < 50000000; i++) {
myArray.array[i] = i * i + 3L;
}
time = System.currentTimeMillis();
myArray.forEach(new Function<Long>() {
public long perform(Long parameter, long x) {
return x * 8 + parameter + 5L;
}
});
System.out.println(System.currentTimeMillis() - time);
System.out.println(myArray.x);
myArray = null;
myArray = new MyArray<Long>(50000000, Long.class, 234553523525L);
for (int i = 0; i < 50000000; i++) {
myArray.array[i] = i * i + 3L;
}
time = System.currentTimeMillis();
myArray.forEach(new Function<Long>() {
public long perform(Long parameter, long x) {
return new Compute(8, 5).compute(parameter, x);
}
});
System.out.println(System.currentTimeMillis() - time);
System.out.println(myArray.x);
}
}
আমার সিস্টেমে নিম্নলিখিত ফলাফল দেয়:
224
-699150247503735895
221
-699150247503735895
220
-699150247503735895
219
-699150247503735895
আমি ওরাকলজেডকে 1.7 আপডেট 6 দিয়ে উবুন্টু 12.10 আলফা চালাচ্ছি।
সাধারণভাবে হটস্পট প্রচুর ইন্ডিয়ারেশন এবং সাধারণ হ্রাসকারী ক্রিয়াকলাপকে অনুকূল করে তোলে, সুতরাং সাধারণভাবে আপনারা তাদের সম্পর্কে চিন্তা করবেন না যতক্ষণ না তাদের সিক্যেন্সে প্রচুর পরিমাণ রয়েছে বা তারা খুব বেশি বাসা বাঁধে না।
অন্যদিকে, লিংকডলিস্টে ইন্ডেক্সড গেট লিংকডলিস্টের জন্য পুনরাবৃত্তির কাছে কল করার চেয়ে ধীর গতির যাতে আপনি পুনরাবৃত্তি ব্যবহার করার সময় পাঠযোগ্যতা ধরে রাখার সময় সেই কার্যকারিতাটি হিট করতে পারবেন (প্রতিটি লুপের ক্ষেত্রে স্পষ্ট বা স্পষ্টতই)।
এমনকি অ্যারেলিস্ট বা ভেক্টরের মতো কিছু কিছু দিয়ে যেখানে "গেট" একটি সহজ অ্যারে লুকআপ, দ্বিতীয় লুপটিতে এখনও অতিরিক্ত ওভারহেড রয়েছে যা প্রথমটি নয়। আমি আশা করব এটি প্রথমটির চেয়ে সামান্য ধীর হবে।
নিশ্চিতভাবে জানার একমাত্র উপায় হ'ল এটি বেঞ্চমার্ক করা, এমনকি এটি যতটা সহজ শোনায় তত সহজ নয় । জেআইটি সংকলক আপনার কোডটিতে খুব অপ্রত্যাশিত জিনিসগুলি করতে পারে।
এখানে অ্যানড্রয়েড বিকাশকারী দলের পার্থক্য সম্পর্কে একটি সংক্ষিপ্ত বিশ্লেষণ দেওয়া হল:
https://www.youtube.com/watch?v=MZOf3pOAM6A
ফলাফলের সেখানে যে হয় একটি পার্থক্য, এবং খুব বড় তালিকা সঙ্গে খুব সংযত পরিবেশে এটি একটি লক্ষণীয় পার্থক্য হতে পারে। তাদের পরীক্ষায়, প্রতিটি লুপের জন্য দ্বিগুণ সময় নেয়। যাইহোক, তাদের পরীক্ষাটি 400,000 পূর্ণসংখ্যার অ্যারেলিস্টের ওপরে ছিল। অ্যারেতে উপাদান প্রতি আসল পার্থক্য ছিল 6 টি মাইক্রোসেকেন্ড । আমি পরীক্ষা করিনি এবং তারা বলে নি, তবে আমি আদিমদের চেয়ে বস্তুগুলি ব্যবহার করে কিছুটা বড় হওয়ার প্রত্যাশা করব, তবে এখনও আপনি যদি লাইব্রেরি কোড তৈরি না করেন যেখানে আপনাকে জিজ্ঞাসা করা হবে তার স্কেল সম্পর্কে কোনও ধারণা নেই unless পুনরাবৃত্তি করতে, আমি মনে করি পার্থক্যটি সম্পর্কে চাপ দেওয়ার মতো নয়।
চলক নাম দ্বারা objectArrayList
, আমি ধরে নিই যে এটির একটি উদাহরণ java.util.ArrayList
। সেক্ষেত্রে পারফরম্যান্সের পার্থক্যটি অবিস্মরণীয় হবে।
অন্যদিকে, এটির উদাহরণস্বরূপ java.util.LinkedList
, List#get(int)
ও (এন) ক্রিয়াকলাপ হওয়ায় দ্বিতীয় পদ্ধতিটি অনেক ধীর হবে ।
সুতরাং লুপটিতে যুক্তি দ্বারা সূচক প্রয়োজন না হলে প্রথম পদ্ধতির সর্বদা পছন্দ করা হয় is
1. for(Object o: objectArrayList){
o.DoSomthing();
}
and
2. for(int i=0; i<objectArrayList.size(); i++){
objectArrayList.get(i).DoSomthing();
}
উভয়ই একই কাজ করে তবে প্রতিটিের জন্য সহজ এবং নিরাপদ প্রোগ্রামিংয়ের ব্যবহারের জন্য, ব্যবহারের ২ য় পদ্ধতিতে ত্রুটিযুক্ত হওয়ার সম্ভাবনা রয়েছে।
এটি অদ্ভুত যে কেউ স্পষ্টরূপে উল্লেখ করেনি - ফোরচ মেমরি বরাদ্দ করে (একটি পুনরুক্তির আকারে), যখন লুপের জন্য কোনও সাধারণ কোনও মেমরি বরাদ্দ করে না। অ্যান্ড্রয়েডে গেমসের জন্য, এটি একটি সমস্যা, কারণ এর অর্থ এই যে আবর্জনা সংগ্রহকারী পর্যায়ক্রমে চলবে। একটি গেমটিতে আপনি আবর্জনা সংগ্রহকারী চালানোর জন্য চান না ... EVER। সুতরাং আপনার অঙ্কন (বা রেন্ডার) পদ্ধতিতে ফোরচ লুপগুলি ব্যবহার করবেন না।
গৃহীত উত্তর প্রশ্নের উত্তর দেয়, অ্যারেলিস্টের ব্যতিক্রমী মামলা বাদে ...
যেহেতু বেশিরভাগ বিকাশকারী অ্যারেলিস্টের উপর নির্ভর করে (অন্তত আমি এটি বিশ্বাস করি)
সুতরাং আমি এখানে সঠিক উত্তর যুক্ত করতে বাধ্য।
সরাসরি বিকাশকারী ডকুমেন্টেশন থেকে: -
লুপের জন্য বর্ধিত (কখনও কখনও "প্রত্যেকের জন্য" লুপ হিসাবেও পরিচিত) সংগ্রহের জন্য ব্যবহার করা যেতে পারে যা আইটেবল ইন্টারফেসটি প্রয়োগ করে এবং অ্যারেগুলির জন্য। সংগ্রহগুলির সাথে, একটি পুনরাবৃত্তিকে হ্যাজনেক্সট () এবং পরবর্তী () এ ইন্টারফেস কল করার জন্য বরাদ্দ করা হয়। একটি অ্যারেলিস্ট সহ, একটি হাতে লিখিত গণনা লুপ প্রায় 3x দ্রুত (জেআইটি সহ বা তার বাইরে) তবে অন্যান্য সংগ্রহের জন্য লুপ সিনট্যাক্সের জন্য বর্ধিত স্পষ্ট আয়রেটর ব্যবহারের সমান হবে।
একটি অ্যারের মাধ্যমে পুনরাবৃত্তি করার জন্য বেশ কয়েকটি বিকল্প রয়েছে:
static class Foo {
int mSplat;
}
Foo[] mArray = ...
public void zero() {
int sum = 0;
for (int i = 0; i < mArray.length; ++i) {
sum += mArray[i].mSplat;
}
}
public void one() {
int sum = 0;
Foo[] localArray = mArray;
int len = localArray.length;
for (int i = 0; i < len; ++i) {
sum += localArray[i].mSplat;
}
}
public void two() {
int sum = 0;
for (Foo a : mArray) {
sum += a.mSplat;
}
}
শূন্য () সবচেয়ে ধীরতম, কারণ লুপের মাধ্যমে প্রতিটি পুনরাবৃত্তির জন্য একবার অ্যারে দৈর্ঘ্য পাওয়ার ব্যয়টিকে জেআইটি এখনও অনুকূল করতে পারে না।
এক () দ্রুত। এটি চেহারাগুলিকে এড়িয়ে সমস্ত কিছু স্থানীয় ভেরিয়েবলের মধ্যে টান দেয়। কেবল অ্যারের দৈর্ঘ্য একটি কার্যকারিতা সুবিধা দেয়।
দুটি () একটি জেআইটিবিহীন ডিভাইসের জন্য দ্রুত এবং একটি জেআইটি সহ ডিভাইসগুলির জন্য এক () থেকে পৃথক। এটি জাভা প্রোগ্রামিং ভাষার 1.5 সংস্করণে প্রবর্তিত লুপ সিনট্যাক্স ব্যবহার করে।
সুতরাং, আপনার ডিফল্টরূপে লুপের জন্য বর্ধিত ব্যবহার করা উচিত, তবে সম্পাদনা-সমালোচনামূলক অ্যারেলিস্ট পুনরাবৃত্তির জন্য হাতে লিখিত গণিত লুপটি বিবেচনা করুন।
হ্যাঁ, for-each
বৈকল্পিক স্বাভাবিকের চেয়ে দ্রুতindex-based-for-loop
।
for-each
বৈকল্পিক ব্যবহার iterator
। সুতরাং ট্র্যাভারসিং স্বাভাবিক for
লুপের চেয়ে দ্রুত যা সূচক ভিত্তিক।
এটি কারণ iterator
ট্র্যাভার্সিংয়ের জন্য অনুকূলিত হয়েছে, কারণ এটি পরের উপাদানটির ঠিক আগে এবং পূর্ববর্তী উপাদানটির ঠিক পরে ইশারা করছে । পড়ার কারণ এক index-based-for-loop
ধীর হতে যে, এটা করতে হবে নিরূপণ এবং উপাদান অবস্থানে প্রতিটি সময় সরাতে যা দিয়ে নয় iterator
।
public class FirstJavaProgram {
public static void main(String[] args)
{
int a[]={1,2,3,45,6,6};
// Method 1: this is simple way to print array
for(int i=0;i<a.length;i++)
{
System.out.print(a[i]+" ");
}
// Method 2: Enhanced For loop
for(int i:a)
{
System.out.print(i+" ");
}
}
}