"জেভিএম টেল-কল অপ্টিমাইজেশান সমর্থন করে না, তাই আমি প্রচুর বিস্ফোরক স্ট্যাকের পূর্বাভাস দিয়েছি"
যে কেউ এটি (1) বলে সে লেজ-কল অপ্টিমাইজেশন বুঝতে পারে না, বা (2) জেভিএম, বা (3) উভয়ই বুঝতে পারে না।
আমি উইকিপিডিয়া থেকে টেইল-কলগুলির সংজ্ঞা দিয়ে শুরু করব (আপনি যদি উইকিপিডিয়া পছন্দ না করেন তবে এখানে একটি বিকল্প আছে ):
কম্পিউটার বিজ্ঞানে, একটি টেইল কল হ'ল একটি সাবরুটিন কল যা এটির চূড়ান্ত ক্রিয়া হিসাবে অন্য পদ্ধতির অভ্যন্তরে ঘটে; এটি একটি রিটার্ন মান উত্পাদন করতে পারে যা তত্ক্ষণাত কলিং পদ্ধতি দ্বারা ফিরে আসে
নীচের কোডে, কলটি bar()
হল এর লেজ কল foo()
:
private void foo() {
// do something
bar()
}
টেইল কল অপ্টিমাইজেশন ঘটে যখন ভাষা প্রয়োগ, একটি লেজ কল দেখে সাধারণ পদ্ধতি আহবান (যা একটি স্ট্যাক ফ্রেম তৈরি করে) ব্যবহার করে না, পরিবর্তে একটি শাখা তৈরি করে। এটি একটি অপ্টিমাইজেশন কারণ স্ট্যাক ফ্রেমের জন্য মেমরির প্রয়োজন হয় এবং ফ্রেমের উপরে তথ্য চাপানোর জন্য সিপিইউ চক্রের প্রয়োজন হয় এবং কারণ কল / রিটার্ন জুটিটি নিঃশর্ত জাম্পের চেয়ে বেশি সিপিইউ চক্রের জন্য অনুমান করা হয়।
টিসিও প্রায়শই পুনরাবৃত্তির জন্য প্রয়োগ করা হয় তবে এটি কেবল এটির ব্যবহার নয়। বা এটি সমস্ত পুনরাবৃত্তির ক্ষেত্রে প্রযোজ্য নয়। একটি ফ্যাক্টরিয়াল গণনা করার জন্য সহজ পুনরাবৃত্ত কোড, উদাহরণস্বরূপ, টেল-কল অনুকূলিতকরণ করা যায় না, কারণ ফাংশনে ঘটে যাওয়া শেষ জিনিসটি একটি গুণ গুণ operation
public static int fact(int n) {
if (n <= 1) return 1;
else return n * fact(n - 1);
}
টেল কল অপ্টিমাইজেশন বাস্তবায়নের জন্য আপনার দুটি জিনিস প্রয়োজন:
- একটি প্ল্যাটফর্ম যা সাবট্রোটিন কলগুলির পাশাপাশি শাখা প্রশাখাকে সমর্থন করে।
- একটি স্ট্যাটিক বিশ্লেষক যা টেল কল অপ্টিমাইজেশন সম্ভব কিনা তা নির্ধারণ করতে পারে।
এটাই. আমি অন্য কোথাও উল্লেখ করেছি যে, জেভিএম (অন্য কোনও টিউরিং-সম্পূর্ণ আর্কিটেকচারের মতো) একটি গোটো আছে। এটি শর্তহীন গোটো হওয়ার কারণে ঘটে থাকে তবে শর্তাধীন শাখা ব্যবহার করে কার্যকারিতাটি সহজেই প্রয়োগ করা যেতে পারে।
স্থিতিশীল বিশ্লেষণ টুকরটি কি জটিল। একক ফাংশনের মধ্যে, এটি কোনও সমস্যা নয়। উদাহরণস্বরূপ, এখানে একটিতে মানগুলি যোগ করতে একটি লেজ-পুনরাবৃত্ত স্কেল ফাংশন রয়েছে List
:
def sum(acc:Int, list:List[Int]) : Int = {
if (list.isEmpty) acc
else sum(acc + list.head, list.tail)
}
এই ফাংশনটি নিম্নলিখিত বাইটকোডে পরিণত হয়:
public int sum(int, scala.collection.immutable.List);
Code:
0: aload_2
1: invokevirtual #63; //Method scala/collection/immutable/List.isEmpty:()Z
4: ifeq 9
7: iload_1
8: ireturn
9: iload_1
10: aload_2
11: invokevirtual #67; //Method scala/collection/immutable/List.head:()Ljava/lang/Object;
14: invokestatic #73; //Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I
17: iadd
18: aload_2
19: invokevirtual #76; //Method scala/collection/immutable/List.tail:()Ljava/lang/Object;
22: checkcast #59; //class scala/collection/immutable/List
25: astore_2
26: istore_1
27: goto 0
goto 0
শেষে নোট করুন । তুলনা করে, একটি সমতুল্য জাভা ফাংশন (যা অবশ্যই Iterator
একটি স্কালার তালিকাটি মাথা এবং লেজে বিভক্ত করার অনুকরণের জন্য ব্যবহার করতে হবে ) নিম্নলিখিত বাইকোডে রূপান্তরিত হয়। নোট যে গত দুটি অপারেশন এখন একটি হয় ডাকা , যে রিকার্সিভ আবাহন দ্বারা উত্পাদিত মান একটি সুনির্দিষ্ট রিটার্ন দ্বারা অনুসরণ করে।
public static int sum(int, java.util.Iterator);
Code:
0: aload_1
1: invokeinterface #64, 1; //InterfaceMethod java/util/Iterator.hasNext:()Z
6: ifne 11
9: iload_0
10: ireturn
11: iload_0
12: aload_1
13: invokeinterface #70, 1; //InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
18: checkcast #25; //class java/lang/Integer
21: invokevirtual #74; //Method java/lang/Integer.intValue:()I
24: iadd
25: aload_1
26: invokestatic #43; //Method sum:(ILjava/util/Iterator;)I
29: ireturn
একটি একক ফাংশন লেঙ্গুড় কল অপ্টিমাইজেশান তুচ্ছ হল: কম্পাইলার দেখতে পারেন কোন কোড কলের ফলাফলের ব্যবহার করে নেই, তাই এটি প্রতিস্থাপন করতে পারেন ডাকা একটি সঙ্গে goto
।
আপনার একাধিক পদ্ধতি থাকলে জীবনটি জটিল হয়ে ওঠে। জেভিএমের শাখা প্রশস্তকরণ নির্দেশাবলী, সাধারণ-উদ্দেশ্য প্রসেসরের মতো, যেমন 80x86, একক পদ্ধতিতে সীমাবদ্ধ। এটি এখনও অপেক্ষাকৃত সহজবোধ্য যদি আপনার ব্যক্তিগত পদ্ধতি থাকে: সংকলকটি সেই পদ্ধতিগুলিকে যথাযথভাবে ইনলাইন করতে বিনামূল্যে, তাই লেজ কলগুলি অনুকূল করতে পারে (যদি আপনি ভাবছেন যে এটি কীভাবে কাজ switch
করতে পারে তবে আচরণ নিয়ন্ত্রণের জন্য ব্যবহার করা একটি সাধারণ পদ্ধতি বিবেচনা করুন )। এমনকি আপনি এই কৌশলটি একই শ্রেণীর একাধিক পাবলিক পদ্ধতিতেও প্রসারিত করতে পারেন: সংকলকটি মেথড বডিগুলিকে ইনলাইন করে, পাবলিক ব্রিজের পদ্ধতি সরবরাহ করে এবং অভ্যন্তরীণ কলগুলি জাম্পগুলিতে পরিণত হয়।
তবে, এই মডেলটি ভেঙে যায় যখন আপনি বিভিন্ন ক্লাসে পাবলিক পদ্ধতিগুলি বিবেচনা করেন, বিশেষত ইন্টারফেস এবং শ্রেণিবদ্ধকারীদের আলোকে। উত্স-স্তরের সংকলকটি কেবল টেল-কল অপ্টিমাইজেশানগুলি প্রয়োগ করতে পর্যাপ্ত জ্ঞান রাখে না। তবে, "বেয়ার-মেটাল" বাস্তবায়নগুলির বিপরীতে , * জেভিএম (হটস্পট সংকলক আকারে এটি করার তথ্য রয়েছে (কমপক্ষে, প্রাক্তন সান সংকলকটি করে)) আমি জানি না এটি আসলে সম্পাদন করে কিনা whether টেল-কল অপ্টিমাইজেশান, এবং সন্দেহ হয় না, তবে এটি পারে ।
কোনটি আমাকে আপনার প্রশ্নের দ্বিতীয় অংশে নিয়ে আসে, যা আমি "আমাদের যত্ন নেওয়া উচিত?"
স্পষ্টতই, যদি আপনার ভাষা পুনরাবৃত্তির জন্য এটির একমাত্র আদিম হিসাবে পুনরাবৃত্তি ব্যবহার করে তবে আপনি যত্নশীল। তবে, যে ভাষাগুলির জন্য এই বৈশিষ্ট্যটির প্রয়োজন রয়েছে তারা এটিকে প্রয়োগ করতে পারে; কেবল ইস্যুটি হ'ল কথিত ভাষার সংকলক এমন কোনও শ্রেণি তৈরি করতে পারে যা একটি যথেচ্ছ জাভা ক্লাস দ্বারা কল এবং কল করতে পারে।
এই ক্ষেত্রে বাইরে, আমি এটি অপ্রাসঙ্গিক তা বলে ডাউনভোটদের আমন্ত্রণ জানাতে যাচ্ছি। আমি দেখা বেশিরভাগ পুনরাবৃত্ত কোড (এবং আমি প্রচুর গ্রাফ প্রকল্পের সাথে কাজ করেছি) টেল-কল অপটিমাইজযোগ্য নয় । সাধারণ ফ্যাকটোরিয়ালটির মতো, এটি রাষ্ট্র গঠনে পুনরাবৃত্তি ব্যবহার করে এবং লেজ অপারেশন সংমিশ্রণ করে।
যে কোডটির জন্য টেল-কল অপটিমাইজযোগ্য, সে কোডটি পুনরাবৃত্ত আকারে অনুবাদ করা প্রায়শই সোজা। উদাহরণস্বরূপ, sum()
আমি যে ফাংশনটি আগে দেখিয়েছি তা সাধারণীকরণ করা যেতে পারে foldLeft()
। যদি আপনি উত্সটি দেখুন , আপনি দেখতে পাবেন যে এটি আসলে একটি পুনরাবৃত্ত অপারেশন হিসাবে প্রয়োগ করা হয়েছে। জার্গ ডব্লু মিতাগের একটি ফাংশন কলের মাধ্যমে প্রয়োগ করা একটি রাষ্ট্রীয় মেশিনের উদাহরণ রয়েছে; প্রচুর দক্ষ (এবং রক্ষণাবেক্ষণযোগ্য) স্টেট মেশিন বাস্তবায়ন রয়েছে যা জাম্পগুলিতে অনুবাদ করা ফাংশন কলগুলির উপর নির্ভর করে না।
আমি সম্পূর্ণ ভিন্ন কিছু দিয়ে শেষ করব। আপনি যদি এসআইসিপি-র পাদটীকা থেকে গুগল করেন তবে আপনি এখানেই শেষ হতে পারেন । আমি ব্যক্তিগতভাবে আমার কম্পাইলার প্রতিস্থাপন থাকার চেয়ে যে একটি আরো অনেক আকর্ষণীয় জায়গা খুঁজে JSR
দ্বারা JUMP
।