ব্লুবার্ডের ইউট. টোস্টপোপার্টি ফাংশন কীভাবে কোনও বস্তুর বৈশিষ্ট্যগুলিকে "দ্রুত" করে তোলে?


165

ব্লুবার্ডের util.jsফাইলে এটির নিম্নলিখিত ফাংশন রয়েছে:

function toFastProperties(obj) {
    /*jshint -W027*/
    function f() {}
    f.prototype = obj;
    ASSERT("%HasFastProperties", true, obj);
    return f;
    eval(obj);
}

কিছু কারণে, রিটার্ন ফাংশনের পরে একটি বিবৃতি আছে, যা আমি নিশ্চিত না কেন এটি সেখানে রয়েছে।

পাশাপাশি, মনে হয় এটি ইচ্ছাকৃত, কারণ লেখক জেএসহিন্টকে এই সম্পর্কে সতর্ক করে দিয়েছিল:

'প্রত্যাবর্তনের' পরে অ্যাক্সেসযোগ্য 'ইওল'। (W027)

এই ফাংশনটি ঠিক কী করে? util.toFastPropertiesআসলেই কি কোনও জিনিসের বৈশিষ্ট্যগুলি "দ্রুত" করে তোলে?

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

উত্তর:


314

2017 আপডেট: প্রথম, আজ পাঠকদের জন্য - এখানে নোড 7 (4+) এর সাথে কাজ করে এমন একটি সংস্করণ এখানে দেওয়া হয়েছে:

function enforceFastProperties(o) {
    function Sub() {}
    Sub.prototype = o;
    var receiver = new Sub(); // create an instance
    function ic() { return typeof receiver.foo; } // perform access
    ic(); 
    ic();
    return o;
    eval("o" + o); // ensure no dead code elimination
}

এক বা দুটি ছোট অপ্টিমাইজেশান স্যানস - নীচের সমস্ত কিছুই এখনও বৈধ।

প্রথমে এটি কী করে এবং কেন এটি দ্রুত এবং তারপরে এটি কেন কাজ করে তা নিয়ে আলোচনা করা যাক।

এর মানে কি

ভি 8 ইঞ্জিন দুটি বস্তুর উপস্থাপনা ব্যবহার করে:

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

এখানে একটি সাধারণ ডেমো যা গতির পার্থক্য দেখায়। এখানে আমরা deleteস্টেটমেন্টটি ধীরে ধীরে অভিধান মোডে জোর করার জন্য ব্যবহার করি ।

যখনই সম্ভব ইঞ্জিন দ্রুত মোড ব্যবহার করার চেষ্টা করে এবং সাধারণত যখনই প্রচুর সম্পত্তি অ্যাক্সেস করা হয় - তবে কখনও কখনও এটি অভিধান মোডে ফেলে দেওয়া হয়। অভিধান মোডে থাকায় একটি বৃহত পারফরম্যান্স পেনাল্টি থাকে তাই সাধারণভাবে বস্তুগুলিকে দ্রুত মোডে রাখাই বাঞ্ছনীয়।

এই হ্যাকটি উদ্দেশ্য মোড থেকে শব্দটিকে দ্রুত মোডে বাধ্য করার উদ্দেশ্যে।

কেন এটি দ্রুত

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

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

কিভাবে এটা কাজ করে

আসুন প্রথমে কোডটি দেখুন এবং প্রতিটি লাইন কী করে তা চিত্রিত করুন:

function toFastProperties(obj) {
    /*jshint -W027*/ // suppress the "unreachable code" error
    function f() {} // declare a new function
    f.prototype = obj; // assign obj as its prototype to trigger the optimization
    // assert the optimization passes to prevent the code from breaking in the
    // future in case this optimization breaks:
    ASSERT("%HasFastProperties", true, obj); // requires the "native syntax" flag
    return f; // return it
    eval(obj); // prevent the function from being optimized through dead code 
               // elimination or further optimizations. This code is never  
               // reached but even using eval in unreachable code causes v8
               // to not optimize functions.
}

আমরা না আছে যে V8 জাহির করা এই অপ্টিমাইজেশান, আমরা পরিবর্তে পারেন না কোড নিজেদেরকে খুঁজে পেতে V8 ইউনিট পরীক্ষা পড়া :

// Adding this many properties makes it slow.
assertFalse(%HasFastProperties(proto));
DoProtoMagic(proto, set__proto__);
// Making it a prototype makes it fast again.
assertTrue(%HasFastProperties(proto));

এই পরীক্ষাটি পড়া এবং চালানো আমাদের দেখায় যে এই অপ্টিমাইজেশনটি সত্যই v8 এ কাজ করে। তবে - এটি দেখতে ভাল লাগবে।

আমরা যদি পরীক্ষা করে objects.ccদেখি আমরা নীচের ফাংশনটি (L9925) খুঁজে পেতে পারি:

void JSObject::OptimizeAsPrototype(Handle<JSObject> object) {
  if (object->IsGlobalObject()) return;

  // Make sure prototypes are fast objects and their maps have the bit set
  // so they remain fast.
  if (!object->HasFastProperties()) {
    MigrateSlowToFast(object, 0);
  }
}

এখন, JSObject::MigrateSlowToFastকেবল স্পষ্টভাবে অভিধান নেওয়া এবং এটিকে দ্রুত ভি 8 অবজেক্টে রূপান্তরিত করে। এটি সার্থকভাবে পড়া এবং ভি 8 অবজেক্ট ইন্টার্নালগুলির মধ্যে একটি আকর্ষণীয় অন্তর্দৃষ্টি - তবে এটি এখানে বিষয় নয়। আমি এখনও আন্তরিকভাবে প্রস্তাব দিচ্ছি যে আপনি এটি এখানে পড়ুন কারণ এটি ভি 8 অবজেক্ট সম্পর্কে জানার ভাল উপায়।

আমরা যদি খুঁজে বার করো SetPrototypeমধ্যে objects.cc, আমরা দেখতে পাচ্ছেন এটি লাইন 12231 ডেকে হয়:

if (value->IsJSObject()) {
    JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value));
}

যার বদলে বলা হয় কোনটি FuntionSetPrototypeআমরা পাই তা দিয়ে .prototype =

করছেন __proto__ =বা .setPrototypeOfকাজও করেছেন তবে এগুলি ES6 ফাংশন এবং ব্লুবার্ড নেটস্কেপ 7 এর পরে সমস্ত ব্রাউজারে রান করে তাই কোডটি এখানে সহজ করার জন্য প্রশ্নটির বাইরে। উদাহরণস্বরূপ, আমরা যদি পরীক্ষা .setPrototypeOfকরি তবে আমরা দেখতে পাচ্ছি:

// ES6 section 19.1.2.19.
function ObjectSetPrototypeOf(obj, proto) {
  CHECK_OBJECT_COERCIBLE(obj, "Object.setPrototypeOf");

  if (proto !== null && !IS_SPEC_OBJECT(proto)) {
    throw MakeTypeError("proto_object_or_null", [proto]);
  }

  if (IS_SPEC_OBJECT(obj)) {
    %SetPrototype(obj, proto); // MAKE IT FAST
  }

  return obj;
}

যা সরাসরি চালু Object:

InstallFunctions($Object, DONT_ENUM, $Array(
...
"setPrototypeOf", ObjectSetPrototypeOf,
...
));

সুতরাং - আমরা পেটকা কোডটি বেয়ার ধাতব দ্বারা লিখিত কোড থেকে পথ চললাম। এটি দুর্দান্ত ছিল।

দাবি পরিত্যাগী:

মনে রাখবেন এটি সমস্ত বাস্তবায়ন বিশদ। পেটকার মতো লোকেরা অপ্টিমাইজেশন ফ্রিক্স। সর্বদা মনে রাখবেন যে অকাল অপটিমাইজেশন হ'ল 97% সময়ের সমস্ত অশুভের মূল। ব্লুবার্ড খুব ঘন ঘন বেসিক কিছু করে তাই এটি এই পারফরম্যান্স হ্যাকগুলি থেকে প্রচুর লাভ করে - কলব্যাক তত দ্রুত হওয়া সহজ নয়। আপনাকে খুব কমই কোডটিতে এমন কিছু করতে হবে যা কোনও লাইব্রেরিকে শক্তি দেয় না।


37
এটি আমি সবচেয়ে আকর্ষণীয় পোস্টটি কিছুক্ষণ পড়েছি। আপনাকে অনেক শ্রদ্ধা এবং প্রশংসা!
এম59

2
@timoxley আমি নিম্নলিখিতটি লিখেছি eval(কোড ওপিতে পোস্ট করা কোডটি ব্যাখ্যা করার সময় কোড মন্তব্যে): "ডেড কোড নির্মূলকরণ বা আরও অনুকূলিতকরণের মাধ্যমে ফাংশনটি অনুকূলিত হওয়া থেকে বিরত রাখুন This এই কোডটি কখনই পৌঁছায় না তবে এমনকি অ্যাক্সেসযোগ্য কোডটি ভি 8 কে অপ্টিমাইজ করে না ফাংশন। " । এখানে একটি সম্পর্কিত পড়া । আপনি কি আমাকে এই বিষয়ে আরও বিস্তারিত জানাতে চান?
বেনিয়ামিন গ্রুইনবাউম

3
@ থেরম্যান একটি 1;"ডিওপিমাইজেশন" সৃষ্টি করবে না, debugger;সম্ভবত তিনিও সমানভাবে কাজ করতে পারতেন। সুন্দর জিনিসটি এমন যে যখন evalকোনও স্ট্রিং নয় এমন কিছু পাস করা হয় এটি এটি দিয়ে কিছুই করে না তাই এটি বরং নিরীহ - if(false){ debugger; }
একধরণের

6
Btw এই কোডটি সাম্প্রতিক v8-র পরিবর্তনের কারণে আপডেট হয়েছে, এখন আপনাকেও নির্মাণকারীর তাত্ক্ষণিক প্রয়োজন। সুতরাং এটি
অলস

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