জেভিএম টেল-কল অপ্টিমাইজেশানের উপর কি সীমাবদ্ধতা আরোপ করে?


36

ক্লোজুর নিজেই টেল কল অপ্টিমাইজেশন সম্পাদন করে না: যখন আপনার একটি লেজ পুনরাবৃত্ত ফাংশন থাকে এবং আপনি এটি অনুকূলিত করতে চান, আপনাকে বিশেষ ফর্মটি ব্যবহার করতে হবে recur। একইভাবে, যদি আপনার দুটি পারস্পরিক পুনরাবৃত্তি ফাংশন থাকে তবে আপনি কেবল সেগুলি ব্যবহার করে সেগুলি অনুকূল করতে পারেন trampoline

স্কালার সংকলকটি পুনরাবৃত্ত ফাংশনের জন্য টিসিও সম্পাদন করতে সক্ষম, তবে দুটি পারস্পরিক পুনরাবৃত্তি ফাংশনের জন্য নয়।

যখনই আমি এই সীমাবদ্ধতাগুলি সম্পর্কে পড়েছি, তারা সর্বদা জেভিএম মডেলের অভ্যন্তরীণ কিছু সীমাবদ্ধতার জন্য দায়ী ছিল। আমি কম্পাইলারগুলি সম্পর্কে বেশ কিছু জানি না, তবে এই ধাঁধাটি আমাকে খানিকটা ধাঁধা দেয়। আমি উদাহরণ থেকে নেওয়া যাক Programming Scala। এখানে ফাংশন

def approximate(guess: Double): Double =
  if (isGoodEnough(guess)) guess
  else approximate(improve(guess))

অনুবাদ করা হয়

0: aload_0
1: astore_3
2: aload_0
3: dload_1
4: invokevirtual #24; //Method isGoodEnough:(D)Z
7: ifeq
10: dload_1
11: dreturn
12: aload_0
13: dload_1
14: invokevirtual #27; //Method improve:(D)D
17: dstore_1
18: goto 2

সুতরাং, বাইটকোড স্তরে, একটি মাত্র প্রয়োজন goto। এই ক্ষেত্রে, আসলে, কঠোর পরিশ্রম কম্পাইলার দ্বারা সম্পন্ন হয়।

অন্তর্নিহিত ভার্চুয়াল মেশিনের কোন সুবিধা সংকলকটিকে আরও সহজে টিসিও হ্যান্ডেল করতে দেয়?

পার্শ্ব নোট হিসাবে, আমি আশা করব না যে আসল মেশিনগুলি জেভিএমের চেয়ে বেশি স্মার্ট হবে। তবুও, অনেকগুলি ভাষা যা হ্যাস্কেলের মতো নেটিভ কোডগুলিতে সংকলন করে, লেজ কলগুলি অনুকূল করার ক্ষেত্রে সমস্যা মনে হয় না (ভাল, হাস্কেলের মাঝে মাঝে অলসতার কারণে হতে পারে, তবে এটি অন্য একটি সমস্যা)।

উত্তর:


25

এখন, ক্লোজার সম্পর্কে এবং স্কালার সম্পর্কে আমি খুব বেশি কিছু জানি না, তবে আমি এটির শট দেব।

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

function forward(obj: Callable<int, int>, arg: int) =
    let arg1 <- arg + 1 in obj.call(arg1)

যদিও এটি এখানে কেবলমাত্র একটি বাচ্চার অদক্ষতা রয়েছে, সেখানে পুরো প্রোগ্রামিং শৈলী রয়েছে (যেমন কন্টিনিয়েশন পাসিং স্টাইল বা সিপিএস) যার টন কল রয়েছে এবং খুব কমই ফিরে আসে। সম্পূর্ণ টিসিও ছাড়াই এটি করার অর্থ আপনি স্ট্যাক স্পেস ছাড়িয়ে যাওয়ার আগে কেবল কোডের ক্ষুদ্র বিটগুলি চালাতে পারবেন।

অন্তর্নিহিত ভার্চুয়াল মেশিনের কোন সুবিধা সংকলকটিকে আরও সহজে টিসিও হ্যান্ডেল করতে দেয়?

একটি লেজ কল নির্দেশ, যেমন লুয়া 5.1 ভিএম-তে। আপনার উদাহরণটি খুব সহজ পাওয়া যায় না। আমার এইরকম কিছু হয়ে যায়:

push arg
push 1
add
load obj
tailcall Callable.call
// implicit return; stack frame was recycled

সিডনোট হিসাবে, আমি আশা করব না যে আসল মেশিনগুলি জেভিএমের চেয়ে বেশি স্মার্ট হবে।

আপনি ঠিক বলেছেন, তারা না। প্রকৃতপক্ষে, তারা কম স্মার্ট এবং স্ট্যাক ফ্রেমের মতো জিনিসগুলি এমনকি (বেশি) জানে না। এ কারণেই কেন কেউ স্ট্যাক স্পেসটি পুনরায় ব্যবহার এবং কোনও রিটার্নের ঠিকানা না দিয়ে কোডে জাম্প দেওয়ার মতো কৌশলগুলি টানতে পারে।


আমি দেখি. আমি বুঝতে পারি নি যে কম স্মার্ট হওয়ার কারণে এমন একটি অপ্টিমাইজেশানটি আসতে পারে যা অন্যথায় নিষিদ্ধ ছিল।
অ্যান্ড্রিয়া

7
+1, জেভিএমেরtailcall জন্য নির্দেশ ইতিমধ্যে 2007 এর প্রথম দিকে প্রস্তাব করা হয়েছে: ওয়েবব্যাক মেশিনের মাধ্যমে সান ডটকমের ব্লগ । ওরাকল টেকওভারের পরে, এই লিঙ্কটি 404 এর। আমার ধারণা, এটি এটি JVM 7 অগ্রাধিকার তালিকায় তৈরি করে নি।
কে.স্টেফ

1
কোনও tailcallনির্দেশনা কেবল একটি লেজ কলকে একটি লেজ কল হিসাবে চিহ্নিত করবে। তখন জেভিএম আসলে অপ্টিমাইজড টেল কলটি সম্পূর্ণ ভিন্ন প্রশ্ন Whether সিএলআই সিআইএলের একটি .tailনির্দেশ উপসর্গ রয়েছে, তবে মাইক্রোসফ্ট 64৪-বিট সিএলআর দীর্ঘকাল এটি অপ্টিমাইজ করে নি। OTOH, আইবিএম J9 জেভিএম করে লেজ কল সনাক্ত এবং তাদের সেরা অনুকূল রূপ দেয়, এটা বলতে যা কল লেজ কল হয় একটি বিশেষ নির্দেশনা ছাড়াই। টিকা লেজ কল ও নিখুঁত লেজ কল সত্যিই লম্ব হয়। (এ ছাড়াও কল যে স্ট্যাটিক্যালি deducing যা লেজ কল বা undecidable হতে পারে থেকে জানিনা।।)
Jörg ডব্লিউ Mittag

@ JörgWMittag আপনি একটি ভাল পয়েন্ট তৈরি করুন, একটি JVM সহজেই প্যাটার্নটি সনাক্ত করতে পারে call something; oreturn। একটি জেভিএম স্পেক আপডেটের প্রাথমিক কাজটি স্পষ্টভাবে টেল-কল নির্দেশ প্রবর্তন করা নয় বরং এই জাতীয় নির্দেশটি অনুকূলিত করা হয়েছে এমন আদেশ দেওয়া to এই জাতীয় নির্দেশ কেবল সংকলক লেখকদের চাকরি সহজ করে তোলে: জেভিএম লেখক সেই নির্দেশের অনুক্রমটি স্বীকৃতি ছাড়াই ম্যাঙ্গাল হওয়ার আগে তা নিশ্চিত করে নিশ্চিত করতে হবে না, এবং এক্স-> বাইটকোড সংকলক নিশ্চিতভাবে বিশ্রাম নিতে পারে যে তাদের বাইকোড হয় অবৈধ বা আসলে অপ্টিমাইজড, কখনও সঠিক-কিন্তু-স্ট্যাক-উপচে পড়া নয়।

@ ডেলানান: ক্রমটি কেবল call something; return;একটি লেজ কলের সমতুল্য হবে যদি ডাকা জিনিসটি স্ট্যাক ট্রেস না জিজ্ঞাসা করে; যদি প্রশ্নে থাকা পদ্ধতিটি ভার্চুয়াল বা ভার্চুয়াল পদ্ধতিতে কল করে, জেভিএমের কাছে স্ট্যাকের বিষয়ে অনুসন্ধান করতে পারে কিনা তা জানার কোনও উপায় থাকবে না।
সুপারক্যাট

12

Clojure লুপগুলিতে লেজ পুনরাবৃত্তির স্বয়ংক্রিয় অপ্টিমাইজেশন সম্পাদন করতে পারে : স্কালার প্রমাণ হিসাবে জেভিএম এ এটি করা সম্ভব।

এটি না করার জন্য এটি একটি নকশার সিদ্ধান্ত ছিল - আপনি recurযদি এই বৈশিষ্ট্যটি চান তবে আপনাকে স্পষ্টভাবে বিশেষ ফর্মটি ব্যবহার করতে হবে । মেল থ্রেড দেখুন পুনরায়: ক্লোজার গুগল গ্রুপে কোনও টেল কল অপ্টিমাইজেশন কেন নেই

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

ভবিষ্যতে JVM এর পুনরাবৃত্তি এই ক্ষমতাটি পাবে সম্ভবত, যদিও সম্ভবত একটি বিকল্প হিসাবে পুরানো কোডের জন্য পিছনে সামঞ্জস্যপূর্ণ আচরণ বজায় রাখা যায়। বলুন, গিকনাইজারে বৈশিষ্ট্যগুলির পূর্বরূপ জাভা 9 এর জন্য এটি তালিকাবদ্ধ করে:

লেজ কল এবং ধারাবাহিকতা যুক্ত করা হচ্ছে ...

অবশ্যই, ভবিষ্যতের রোডম্যাপগুলি সর্বদা পরিবর্তনের সাপেক্ষে।

দেখা যাচ্ছে যে যাইহোক, এটি এত বড় ব্যাপার নয়। ক্লোজারকে কোডিংয়ের 2 বছরেরও বেশি সময় ধরে আমি কখনই এমন পরিস্থিতিতে পৌঁছতে পারি নি যেখানে টিসিওর অভাবই একটি সমস্যা ছিল। এর মূল কারণগুলি হ'ল:

  • আপনি ইতিমধ্যে 99% সাধারণ ক্ষেত্রে recurবা একটি লুপের জন্য দ্রুত লেজ পুনরাবৃত্তি পেতে পারেন । পারস্পরিক পুচ্ছ পুনরাবৃত্তি কেস সাধারণ কোডে খুব বিরল
  • এমনকি যখন আপনার পারস্পরিক পুনরাবৃত্তি প্রয়োজন, প্রায়শই পুনরাবৃত্তির গভীরতা যথেষ্ট অগভীর যে আপনি কেবল এটি টিসিও ছাড়াই স্ট্যাকের মধ্যে করতে পারেন। টিসিও হ'ল সর্বোপরি একটি "অনুকূলিতকরণ" ....
  • খুব বিরল ক্ষেত্রে যেখানে আপনার অ-স্ট্যাক-গ্রাসকারী পারস্পরিক পুনরাবৃত্তির কিছু ফর্মের প্রয়োজন আছে সেখানে প্রচুর অন্যান্য বিকল্প রয়েছে যা একই লক্ষ্য অর্জন করতে পারে: অলস ক্রম, ট্রাম্পলাইনস ইত্যাদি

"ভবিষ্যতের পুনরাবৃত্তি" - গিকনাইজারে বৈশিষ্ট্যগুলির পূর্বরূপ জাভা 9 এর জন্য বলেছেন: লেজ কল এবং ধারাবাহিকতা যুক্ত করা - এটি কি তাই?
gnat

1
হ্যাঁ - এটি। অবশ্যই, ভবিষ্যতের রোডম্যাপগুলি সর্বদা পরিবর্তনের সাপেক্ষে ....
মাইক্রা

5

সিডনোট হিসাবে, আমি আশা করব না যে আসল মেশিনগুলি জেভিএমের চেয়ে বেশি স্মার্ট হবে।

এটি বুদ্ধিমান হওয়ার বিষয়ে নয়, আলাদা হওয়ার বিষয়ে। সম্প্রতি অবধি, জেভিএম একক ভাষার (জাভা, স্পষ্টতই) নকশাকৃত এবং একচেটিয়াভাবে অপ্টিমাইজ করা হয়েছিল, যার খুব কড়া মেমরি এবং কলিং মডেল রয়েছে।

কেবল কোনও gotoবা পয়েন্টার ছিল না, এমনকি 'বেয়ার' ফাংশন (এমনকি এটি কোনও শ্রেণীর মধ্যে সংজ্ঞায়িত পদ্ধতি ছিল না) কল করার কোনও উপায় ছিল না।

ধারণামূলকভাবে, জেভিএমকে টার্গেট করার সময়, একটি সংকলক লেখককে জিজ্ঞাসা করতে হবে "আমি জাভা পদে এই ধারণাটি কীভাবে প্রকাশ করতে পারি?" এবং স্পষ্টতই, জাভাতে টিসিও প্রকাশ করার কোনও উপায় নেই।

নোট করুন যে এগুলিকে JVM এর ব্যর্থতা হিসাবে দেখা হয় না, কারণ এগুলি জাভার জন্য প্রয়োজন হয় না। জাভা যেমন এই জাতীয় কিছু বৈশিষ্ট্য প্রয়োজন তাড়াতাড়ি এটি JVM এ যুক্ত করা হয়।

এটি সম্প্রতি সম্প্রতি জাভা কর্তৃপক্ষগুলি জাভা-বিহীন ভাষার জন্য প্ল্যাটফর্ম হিসাবে জেভিএমকে গুরুত্বের সাথে নিতে শুরু করেছে, তাই এটি ইতিমধ্যে জাভা সমতুল্য বৈশিষ্ট্যগুলির জন্য কিছুটা সমর্থন পেয়েছে। সর্বাধিক পরিচিত হ'ল ডায়নামিক টাইপিং, যা ইতিমধ্যে JVM এ রয়েছে তবে জাভাতে নয়।


3

সুতরাং, বাইটকোড স্তরে, কেবলমাত্র গোটো দরকার। এই ক্ষেত্রে, আসলে, কঠোর পরিশ্রম কম্পাইলার দ্বারা সম্পন্ন হয়।

আপনি কি লক্ষ্য করেছেন যে পদ্ধতির ঠিকানাটি 0 দিয়ে শুরু হয়? যে সমস্ত পদ্ধতিতে 0 দিয়ে শুরু হয়? জেভিএম একজনকে কোনও পদ্ধতির বাইরে ঝাঁপিয়ে পড়ার অনুমতি দেয় না।

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

অবশ্যই সমস্যাটি হ'ল আপনি সত্যই গ্যারান্টি দিতে পারবেন না যে একই শ্রেণীর অন্যান্য পদ্ধতিগুলি হবে যেখানে অন্যান্য শ্রেণীর অনেক কম পদ্ধতি। আমি সন্দেহ করি যে জেভিএম পদ্ধতিগুলি কোথায় লোড করবে সে সম্পর্কে কোনও গ্যারান্টি দেয়, যদিও আমি সংশোধন করে খুশি হব।


ভাল যুক্তি. তবে টেল-কলটি একটি স্ব-পুনরাবৃত্ত ফাংশনটি অনুকূল করে তোলার জন্য আপনার প্রয়োজন সমস্ত একই পদ্ধতির মধ্যে একটি গোটো । সুতরাং এই সীমাবদ্ধতা স্ব-পুনরাবৃত্ত পদ্ধতির টিসিওকে অস্বীকার করে না।
অ্যালেক্স
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.