সাধারণভাবে গতিশীল বাইন্ডিং বনাম লেক্সিকাল বাইন্ডিং
নিম্নলিখিত উদাহরণ বিবেচনা করুন:
(let ((lexical-binding nil))
(disassemble
(byte-compile (lambda ()
(let ((foo 10))
(message foo))))))
এটি lambda
স্থানীয় ভেরিয়েবলের সাথে একটি সাধারণকে সংকলন এবং তাত্ক্ষণিকভাবে বিচ্ছিন্ন করে । সঙ্গে lexical-binding
অক্ষম করা হলে, উপরের হিসাবে, নিম্নরূপ বাইট কোড দেখায়:
0 constant 10
1 varbind foo
2 constant message
3 varref foo
4 call 1
5 unbind 1
6 return
varbind
এবং varref
নির্দেশাবলী নোট করুন । এই নির্দেশাবলী হিপ মেমরির একটি বৈশ্বিক বাঁধার পরিবেশে তাদের নামের সাথে যথাক্রমে পরিবর্তনশীলগুলি বাঁধাই এবং অনুসন্ধান করে । এর সবগুলিই পারফরম্যান্সে বিরূপ প্রভাব ফেলে: এতে স্ট্রিং হ্যাশিং এবং তুলনা , গ্লোবাল ডেটা অ্যাক্সেসের জন্য সিঙ্ক্রোনাইজেশন এবং পুনরাবৃত্তি হিপ মেমরি অ্যাক্সেস যা সিপিইউ ক্যাচিংয়ের সাথে খারাপভাবে খেলে। এছাড়াও, গতিশীল ভেরিয়েবল বাইন্ডিংগুলি শেষের দিকে তাদের পূর্বের চলকটিতে পুনরুদ্ধার করা দরকার , যা বাইন্ডিংগুলির সাথে প্রতিটি ব্লকের জন্য অতিরিক্ত লুকআপ যুক্ত করে ।let
n
let
n
আপনি যদি উপরের উদাহরণে আবদ্ধ lexical-binding
হন t
তবে বাইট কোডটি কিছুটা পৃথক দেখাচ্ছে:
0 constant 10
1 constant message
2 stack-ref 1
3 call 1
4 return
নোট করুন varbind
এবং varref
সম্পূর্ণরূপে চলে গেছে। স্থানীয় পরিবর্তনশীলগুলি কেবল স্ট্যাকের উপরে ধাক্কা দেওয়া হয় এবং stack-ref
নির্দেশের মাধ্যমে ধ্রুবক অফসেট দ্বারা উল্লেখ করা হয় । মূলত, চলকটি আবদ্ধ এবং ধ্রুবক সময় সহ পড়া হয় , ইন-স্ট্যাক মেমরিটি পড়ে এবং লেখে, যা পুরোপুরি স্থানীয় এবং এইভাবে একত্রে এবং সিপিইউ ক্যাচিংয়ের সাথে ভাল খেলে এবং কোনও স্ট্রিং জড়িত না।
সাধারণত, (যেমন স্থানীয় ভেরিয়েবল আভিধানিক বাঁধাই লুক-সঙ্গে let
, setq
ইত্যাদি) আছে অনেক কম রানটাইম এবং মেমরি জটিলতা ।
এই নির্দিষ্ট উদাহরণ
ডায়নামিকাল বাইন্ডিংয়ের সাথে, প্রতিটি কারণে উপরোক্ত কারণে একটি পারফরম্যান্স জরিমানা জোগায়। আরও বেশি দেয়, তত বেশি গতিশীল পরিবর্তনশীল বাইন্ডিং।
উল্লেখযোগ্যভাবে, দেহের let
অভ্যন্তরে অতিরিক্ত অতিরিক্ত loop
, বাউন্ড ভেরিয়েবলটি লুপের প্রতিটি পুনরাবৃত্তিতে পুনরুদ্ধার করা প্রয়োজন এবং প্রতিটি পুনরাবৃত্তিতে অতিরিক্ত ভেরিয়েবল লক যোগ করতে হবে । অতএব, লুপের দেহ থেকে দূরে রাখা আরও দ্রুত, যাতে সম্পূর্ণ লুপটি শেষ হওয়ার পরে পুনরাবৃত্তির পরিবর্তনশীল কেবল একবার পুনরায় সেট করা যায়। যাইহোক, এটি বিশেষভাবে মার্জিত নয়, কারণ পুনরাবৃত্তকরণ পরিবর্তনশীল এটির প্রয়োজনীয়তার আগেই আবদ্ধ।
লেক্সিকাল বাইন্ডিং সহ, এসগুলি let
সস্তা। উল্লেখযোগ্যভাবে, একটি let
লুপের দেহের অভ্যন্তরে থাকা একটি লুপের দেহের let
বাইরের চেয়ে খারাপ (কর্মক্ষমতা অনুযায়ী) হয় না । সুতরাং, স্থানীয় হিসাবে ভেরিয়েবলগুলিকে যথাসম্ভব বেঁধে দেওয়া, এবং পুনরাবৃত্তকরণের পরিবর্তনশীলটিকে লুপের শরীরে সীমাবদ্ধ রাখা পুরোপুরি ঠিক।
এটি সামান্য দ্রুত, কারণ এটি অনেক কম নির্দেশাবলীর সংকলন করে। পাশের পাশের বিচ্ছিন্নতা (ডানদিকে স্থানীয় যাক) বিবেচনা করুন:
0 varref list 0 varref list
1 constant nil 1:1 dup
2 varbind it 2 goto-if-nil-else-pop 2
3 dup 5 dup
4 varbind temp 6 car
5 goto-if-nil-else-pop 2 7 stack-ref 1
8:1 varref temp 8 cdr
9 car 9 discardN-preserve-tos 2
10 varset it 11 goto 1
11 varref temp 14:2 return
12 cdr
13 dup
14 varset temp
15 goto-if-not-nil 1
18 constant nil
19:2 unbind 2
20 return
পার্থক্যটি কী কারণে ঘটছে তা সম্পর্কে আমার কোনও ধারণা নেই।
varbind
লেক্সিকাল বাইন্ডিং এর অধীনে সংকলিত কোডের কোনও নেই । এটাই পুরো বিষয়টি এবং উদ্দেশ্য।