ননকন্টিচিউস অ্যারে পারফর্ম্যান্ট?


12

সি # তে, যখন কোনও ব্যবহারকারী একটি তৈরি করে List<byte>এবং এতে বাইট যুক্ত করে, তখন এমন একটি সুযোগ থাকে যে এটি স্থানের বাইরে চলে যায় এবং আরও স্থান বরাদ্দ করা দরকার। এটি পূর্ববর্তী অ্যারের আকারের দ্বিগুণ (বা অন্য কোনও গুণক) বরাদ্দ করে, বাইটগুলি অনুলিপি করে এবং পুরানো অ্যারের রেফারেন্সটি বাতিল করে দেয়। আমি জানি যে তালিকাটি তাত্পর্যপূর্ণভাবে বৃদ্ধি পায় কারণ প্রতিটি বরাদ্দ ব্যয়বহুল এবং এটি O(log n)বরাদ্দের মধ্যে সীমাবদ্ধ করে , যেখানে 10প্রতিবার কেবল অতিরিক্ত আইটেম যুক্ত করার ফলে O(n)বরাদ্দ হবে।

তবে বড় অ্যারে মাপের জন্য প্রচুর নষ্ট স্থান হতে পারে, প্রায় অর্ধেক অ্যারে হতে পারে। স্মৃতি হ্রাস করতে আমি একই ধরণের ক্লাস লিখেছিলাম NonContiguousArrayListযা List<byte>ব্যাকিং স্টোর হিসাবে ব্যবহার করে যদি তালিকায় 4MB এর চেয়ে কম থাকে তবে NonContiguousArrayListআকারে বৃদ্ধি পাওয়ায় এটি অতিরিক্ত 4MB বাইট অ্যারে বরাদ্দ করবে ।

List<byte>এই অ্যারেগুলির বিপরীতে স্বাতন্ত্র্যযুক্ত তাই চারপাশে কোনও অনুলিপি নেই, কেবল একটি অতিরিক্ত 4 এম বরাদ্দ। যখন কোনও আইটেমটি সন্ধান করা হয়, তখন সূচকটি 4 এম দ্বারা বিভক্ত হয়ে অ্যারের সাথে থাকা অ্যারের সূচকটি পাওয়া যায়, তারপরে অ্যারির মধ্যে সূচকটি পেতে 4 এম মোড্যুলু হয়।

আপনি কি এই পদ্ধতির সাথে সমস্যাগুলি চিহ্নিত করতে পারেন? এখানে আমার তালিকা:

  • অ-সংযুক্ত অ্যারেতে ক্যাশে লোকেশন নেই যার ফলস্বরূপ খারাপ পারফরম্যান্স হয়। তবে একটি 4 এম ব্লকের আকারে দেখে মনে হচ্ছে ভাল ক্যাশিংয়ের জন্য যথেষ্ট লোকেশন থাকবে।
  • কোনও আইটেম অ্যাক্সেস করা ততটা সহজ নয়, ইন্ডিয়ারেশনের একটি অতিরিক্ত স্তর রয়েছে। এই কি দূরে অপ্টিমাইজড পাবেন? এটি কি ক্যাশে সমস্যা সৃষ্টি করবে?
  • যেহেতু 4M সীমা হিট হওয়ার পরে রৈখিক বৃদ্ধি রয়েছে, তাই আপনি সাধারণত আপনার চেয়ে অনেক বেশি বরাদ্দ রাখতে পারেন (বলুন, 1GB মেমরির জন্য সর্বাধিক 250 টি বরাদ্দ)। 4 এম এর পরে কোনও অতিরিক্ত মেমরি অনুলিপি করা হয়নি, তবে আমি নিশ্চিত নই যে অতিরিক্ত বরাদ্দ মেমরির বিশাল অংশগুলি অনুলিপি করার চেয়ে বেশি ব্যয়বহুল।

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

3
যদি আপনি একটি সংকলনে 4 মিলিয়নেরও বেশি উপাদান নিয়ে কাজ করছেন তবে আমি প্রত্যাশা করি যে ধারক মাইক্রো-অপ্টিমাইজেশন আপনার পারফরম্যান্স উদ্বেগগুলির মধ্যে সবচেয়ে কম।
তেলস্তিন

2
আপনি যা বর্ণনা করছেন তা একটি নিবন্ধিত লিঙ্কযুক্ত তালিকার মতো (খুব বড় নোড সহ)। তাদের ক্যাশে লোকেশন নেই বলে আপনার দাবিটি কিছুটা ভুল। একটি মাত্র ক্যাশে লাইনের ভিতরে কেবল অ্যারের অনেকগুলি মানানসই; আসুন 64 বাইট বলুন। সুতরাং প্রতি 64 বাইটে আপনার ক্যাশে মিস থাকবে। এখন একটি অনিবন্ধিত লিঙ্কযুক্ত তালিকা বিবেচনা করুন যার নোডগুলি স্পষ্টভাবে 64 বাইটের বড় (আবর্জনা সংগ্রহের জন্য অবজেক্ট শিরোনাম সহ) এর কয়েকটি একাধিক। আপনি এখনও প্রতি 64 বাইটে কেবল একটি ক্যাশে মিস পেতে চাইবেন এবং নোডগুলি মেমরির সাথে সংলগ্ন নয় এমনটিও নয়।
ডোভাল

@ দোভাল এটি আসলে একটি নিবন্ধবিহীন লিঙ্কযুক্ত তালিকা নয়, যেহেতু 4M অংশগুলি নিজেই একটি অ্যারেতে সঞ্চিত রয়েছে, সুতরাং যে কোনও উপাদান অ্যাক্সেস করা O (1) ও (এন / বি) নয় যেখানে বি ব্লকের আকার।

2
@ ব্যবহারকারী 2313838 যদি 1000MB মেমরি থাকে এবং 350MB অ্যারে থাকে তবে অ্যারে বাড়ানোর জন্য প্রয়োজনীয় মেমরিটি 1050MB হবে যা পাওয়া যায় তার চেয়ে বড়, এটিই মূল সমস্যা, আপনার কার্যকর সীমাটি আপনার মোট স্থান 1/3 তম। TrimExcessতালিকাটি ইতিমধ্যে তৈরি করা হয় কেবল তখনই সহায়তা করবে এবং তারপরেও এর অনুলিপিটির জন্য এখনও পর্যাপ্ত জায়গা প্রয়োজন।
noisecapella

উত্তর:


5

আপনার উল্লিখিত আঁশগুলিতে, উদ্বেগগুলি আপনার উল্লেখ করা থেকে সম্পূর্ণ পৃথক।

ক্যাশে লোকাল

  • দুটি সম্পর্কিত ধারণা আছে:
    1. লোকেশন, একই ক্যাশে লাইনের (স্থানিক লোকাল) ডেটার পুনরায় ব্যবহার যা সম্প্রতি দেখা হয়েছিল (অস্থায়ী লোকাল)
    2. স্বয়ংক্রিয় ক্যাশে প্রিফেচিং (স্ট্রিমিং)।
  • আপনি যে স্কেলগুলিতে উল্লেখ করেছেন (চার গিগাবাইটে একশ এমবি), মেমোরি বিন্যাসের চেয়ে এই দুটি কারণের আপনার ডেটা উপাদান অ্যাক্সেসের ধরণটি আরও বেশি করতে পারে।
  • আমার (নিখুঁত) ভবিষ্যদ্বাণীটি হ'ল পরিসংখ্যানগতভাবে বিশাল দৈর্ঘ্যের স্মৃতি বরাদ্দের চেয়ে বেশি পারফরম্যান্সের পার্থক্য থাকতে পারে না। লাভ নেই, ক্ষতি নেই।

ডেটা উপাদান অ্যাক্সেস প্যাটার্ন

  • এই নিবন্ধটি দৃশ্যত চিত্রিত করে যে কীভাবে মেমরি অ্যাক্সেস প্যাটার্নগুলি কার্য সম্পাদনকে প্রভাবিত করবে।
  • সংক্ষেপে, কেবল মনে রাখবেন যে আপনার অ্যালগরিদম যদি ইতিমধ্যে মেমরি ব্যান্ডউইথ দ্বারা আটকানো থাকে তবে পারফরম্যান্সের উন্নতির একমাত্র উপায় হ'ল ইতিমধ্যে ক্যাশে লোড হওয়া ডেটা দিয়ে আরও দরকারী কাজ করা।
  • অন্য কথায়, এমনকি যদি YourList[k]এবং YourList[k+1]ক্রমাগত হওয়ার উচ্চ সম্ভাবনা থাকে (না হওয়ার সম্ভাবনা চার মিলিয়নের মধ্যে একটি) তবে আপনি যদি এলোমেলোভাবে আপনার তালিকাটি অ্যাক্সেস করেন বা বৃহত্তর অনির্দেশ্য পদক্ষেপে উদাহরণস্বরূপ, এই কার্য সম্পাদনকে সাহায্য করবে না egwhile { index += random.Next(1024); DoStuff(YourList[index]); }

জিসি সিস্টেমের সাথে ইন্টারঅ্যাকশন

  • আমার মতে, এখানেই আপনার সর্বাধিক দৃষ্টি নিবদ্ধ করা উচিত।
  • সর্বনিম্ন, আপনার ডিজাইন কীভাবে ইন্টারঅ্যাক্ট করবে তা বুঝতে হবে:
  • আমি এই বিষয়গুলিতে জ্ঞানী নই তাই আমি অন্যকে অবদানের জন্য ছেড়ে দেব।

ওভারহেড অ্যাড্রেস অফসেট গণনা

  • টিপিকাল সি # কোড ইতিমধ্যে অ্যাস্রেসেটের অফসেট গণনাগুলি অনেক করছে, সুতরাং আপনার স্কিমের অতিরিক্ত ওভারহেড কোনও সিলে অ্যারেতে কাজ করা টিপিকাল সি # কোডের চেয়ে খারাপ কিছু হবে না।
    • মনে রাখবেন যে সি # কোড অ্যারে রেঞ্জ চেকিংও করে; এবং এই সত্যটি সি ++ কোডের সাথে তুলনীয় অ্যারে প্রসেসিং পারফরম্যান্সে পৌঁছতে সি # কে বাধা দেয় না।
    • কারণটি হ'ল পারফরম্যান্স বেশিরভাগ ক্ষেত্রে মেমরি ব্যান্ডউইথ দ্বারা বাধা হয়ে থাকে।
    • মেমরি ব্যান্ডউইথ থেকে ইউটিলিটি সর্বাধিক করার কৌশলটি মেমরি রিড / রাইটিং ক্রিয়াকলাপগুলির জন্য সিমডি নির্দেশাবলী ব্যবহার করা instructions আদর্শ সি # বা টিপিকাল সি ++ উভয়ই এটি করে না; আপনাকে লাইব্রেরি বা ভাষা অ্যাড-অন্সে অবলম্বন করতে হবে।

উদাহরণস্বরূপ:

  • ঠিকানা গণনা করুন
  • (ও.পি. এর ক্ষেত্রে, শঙ্কার ভিত্তি ঠিকানা লোড করুন (যা ইতিমধ্যে ক্যাশে রয়েছে) এবং তারপরে আরও ঠিকানা গণনা করুন)
  • উপাদান ঠিকানা থেকে / লিখুন পড়ুন

শেষ পদক্ষেপটি এখনও সময়ের সিংহের অংশ নেয়।

ব্যক্তিগত পরামর্শ

  • আপনি একটি CopyRangeফাংশন সরবরাহ করতে পারেন , যা ফাংশনের মতো আচরণ করবে Array.Copyতবে এটি আপনার দুটি উদাহরণের NonContiguousByteArrayমধ্যে বা একটি উদাহরণ এবং অন্য একটি সাধারণের মধ্যে পরিচালনা করবে byte[]। এই ফাংশনগুলি সর্বাধিক মেমরি ব্যান্ডউইথের ব্যবহারের জন্য সিমডি কোড (সি ++ বা সি #) ব্যবহার করতে পারে এবং তারপরে আপনার সি # কোড একাধিক ডিফারেন্সিং বা ঠিকানা গণনার ওভারহেড ছাড়াই অনুলিপিপ্রাপ্ত পরিসরে কাজ করতে পারে।

ব্যবহারযোগ্যতা এবং আন্তঃঅযুক্তি উদ্বেগ

  • স্পষ্টতই আপনি এটিকে NonContiguousByteArrayকোনও সি #, সি ++ বা বিদেশী ভাষার লাইব্রেরি ব্যবহার করতে পারবেন না যা প্রত্যাশিত বাইট অ্যারে বা পিন করা যায় এমন বাইট অ্যারে প্রত্যাশা করে
  • তবে, আপনি যদি নিজের নিজস্ব সি ++ এক্সিলারেশন লাইব্রেরি লিখেন (পি / ইনভোক বা সি ++ / সিএলআই সহ), আপনি অন্তর্নিহিত কোডটিতে বেশ কয়েকটি 4 এমবি ব্লকের বেস ঠিকানাগুলির একটি তালিকাতে পাস করতে পারেন।
    • উদাহরণস্বরূপ, যদি আপনি শুরু উপাদান অ্যাক্সেস দিতে (3 * 1024 * 1024)এবং বিভক্তি (5 * 1024 * 1024 - 1), এর মানে হল এক্সেস জুড়ে জুড়ে হবে chunk[0]এবং chunk[1]। তারপরে আপনি বাইট অ্যারেগুলির একটি অ্যারে (আকার 2) (আকার 2 এম) তৈরি করতে পারেন, এই খণ্ড ঠিকানাগুলি পিন করুন এবং তাদের অন্তর্নিহিত কোডটিতে পাস করতে পারেন।
  • আর একটি ব্যবহারযোগ্যতার উদ্বেগ হ'ল আপনি IList<byte>ইন্টারফেসটি দক্ষতার সাথে কার্যকর করতে পারবেন না : Insertএবং Removeপ্রক্রিয়া করতে খুব বেশি সময় লাগবে কারণ তাদের O(N)সময় প্রয়োজন ।
    • প্রকৃতপক্ষে, দেখে মনে হচ্ছে আপনি ব্যতীত অন্য কোনও কিছুই প্রয়োগ করতে পারবেন না IEnumerable<byte>, অর্থাৎ এটি ক্রমানুসারে স্ক্যান করা যেতে পারে এবং এটিই।

2
আপনি মনে করেন যে ডেটা স্ট্রাকচারের মূল সুবিধাটি মিস করেছেন, এটি হ'ল এটি আপনাকে মেমরির বাইরে চলে না গিয়ে খুব বড় তালিকা তৈরি করতে দেয়। তালিকা <T> সম্প্রসারণ করার সময়, এটি পুরানোটির চেয়ে দ্বিগুণ বড় একটি নতুন অ্যারের প্রয়োজন এবং উভয়কে একই সময়ে স্মৃতিতে উপস্থিত থাকতে হবে।
ফ্রাঙ্ক হিলিমান

6

এটি লক্ষণীয় যে সি ++ এর ইতিমধ্যে স্ট্যান্ডার্ড, দ্বারা একটি সমতুল্য কাঠামো রয়েছে std::deque। বর্তমানে, স্ট্যান্ডের এলোমেলো-অ্যাক্সেস ক্রমের প্রয়োজনের জন্য এটি ডিফল্ট পছন্দ হিসাবে প্রস্তাবিত।

বাস্তবতাটি হ'ল সংঘবদ্ধ মেমোরিটি প্রায় সম্পূর্ণ অপ্রয়োজনীয় যখন ডেটা নির্দিষ্ট আকারের অতীত হয়ে যায় - একটি ক্যাশে লাইনটি কেবলমাত্র 64 বাইট এবং একটি পৃষ্ঠার আকার মাত্র 4-8KB হয় (সাধারণত আদর্শ মান)। একবার আপনি কয়েকটি এমবি সম্পর্কে কথা বলতে শুরু করলে এটি উদ্বেগ হিসাবে উইন্ডোটি সত্যই বাইরে চলে যায়। বরাদ্দ ব্যয়ের ক্ষেত্রেও একই কথা। সমস্ত তথ্য প্রক্রিয়াকরণের মূল্য - এমনকি কেবল এটি পড়তে - যেভাবেই বরাদ্দের দামকে বামন করে।

এটি নিয়ে উদ্বেগের একমাত্র অন্য কারণটি হ'ল সি এপিআইয়ের সাথে ইন্টারফেস করা। তবে আপনি যেভাবেই কোনও তালিকার বাফারে পয়েন্টার পেতে পারেন না তাই এখানে কোনও উদ্বেগ নেই।


এটি আকর্ষণীয়, আমি জানতাম না যে dequeএকইরকম বাস্তবায়ন হয়েছে
নয়েসকেপেলা

কে বর্তমানে স্ট্যান্ড :: ডেক? আপনি একটি উত্স প্রদান করতে পারেন? আমাকে সর্বদা ভাবা হত std :: ভেক্টর হ'ল প্রস্তাবিত ডিফল্ট পছন্দ।
টেম্পজ

std::dequeবাস্তবে অত্যন্ত নিরুৎসাহিত, আংশিক কারণ এমএস স্ট্যান্ডার্ড লাইব্রেরি বাস্তবায়ন এতটাই খারাপ।
সেবাস্তিয়ান রেডল

3

যখন আপনার ডেটা স্ট্রাকচারের সাব-অ্যারেগুলির মতো মেমরি খণ্ডগুলি বিভিন্ন সময়ে নির্দিষ্ট সময়ে বরাদ্দ করা হয়, তারা মেমরিতে একে অপরের থেকে অনেক দূরে অবস্থিত হতে পারে। এটি সমস্যা কিনা বা না তা সিপিইউর উপর নির্ভর করে এবং এর আর ভবিষ্যদ্বাণী করা খুব কঠিন। আপনি এটি পরীক্ষা করতে হবে।

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

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

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

আমি অভিধানগুলির জন্য হ্যাশ টেবিলগুলি অনুরূপ কাঠামো তৈরি করেছি। .NET ফ্রেমওয়ার্ক সরবরাহিত অভিধানে তালিকার মতো একই সমস্যা রয়েছে। শব্দভাণ্ডারগুলি এর মধ্যে কঠোর হয় যে আপনি পাশাপাশি পুনঃস্থাপন এড়াতে হবে।


একটি সংযোগকারী সংগ্রাহক একে অপরের পাশে খণ্ডগুলি সংযোগ করতে পারে।
মৃত এমএমজি

@ ডেড এমজি আমি এমন পরিস্থিতিটির কথা উল্লেখ করছিলাম যেখানে এটি ঘটতে পারে না: এর মধ্যে অন্য অংশগুলি রয়েছে, এটি আবর্জনা নয়। <T> তালিকা সহ, আপনি আপনার অ্যারের জন্য স্বতন্ত্র মেমরির গ্যারান্টিযুক্ত। ভাগ্যহীন তালিকার সাথে, স্মৃতিটি কেবলমাত্র একটি অংশের মধ্যেই সুস্পষ্ট, যদি না আপনার উল্লেখযোগ্য ভাগ্যসংযোগের পরিস্থিতি থাকে। তবে কোনও সংযোগের জন্য প্রচুর পরিমাণে ডেটা স্থানান্তরিত হওয়া প্রয়োজন হতে পারে এবং বড় অ্যারেগুলি বৃহত অবজেক্ট হিপগুলিতে যায়। এটা জটিল.
ফ্র্যাঙ্ক হিলিমান

2

4 এম ব্লকের আকারের সাথে এমনকি একটি একক ব্লকও শারীরিক স্মৃতিতে সামঞ্জস্য হওয়ার গ্যারান্টিযুক্ত নয়; এটি একটি সাধারণ ভিএম পৃষ্ঠার আকারের চেয়ে বড়। লোকালটি সেই স্কেলে অর্থবহ নয়।

আপনাকে হ্যাপ বিভাজন সম্পর্কে উদ্বেগ করতে হবে: যদি বরাদ্দগুলি এমন ঘটে যে আপনার ব্লকগুলি মূলত স্তূপের সাথে স্বতঃস্ফূর্ত হয়, তবে যখন তারা জিসি দ্বারা পুনরুদ্ধার করা হয়, আপনি একটি গাদা দিয়ে শেষ করবেন যা খুব খণ্ডিত হতে পারে পরবর্তী বরাদ্দ। এটি সাধারণত আরও খারাপ পরিস্থিতি কারণ সম্পর্কহীন জায়গায় ব্যর্থতা ঘটে এবং সম্ভবত অ্যাপ্লিকেশনটি পুনরায় চালু করতে বাধ্য করে।


কমপ্যাক্টিং জিসিগুলি খণ্ড বিহীন।
মৃত এমএমজি

এটি সত্য, তবে LOH সংযোগ কেবলমাত্র নেট নেট হিসাবে পাওয়া যায় 4.5 যদি আমি সঠিকভাবে স্মরণ করি।
ব্যবহারকারী 2313838

স্ট্যান্ডের কপি অন-রিলোকেশন আচরণের চেয়ে হিপ কমপ্যাকশনটিতে আরও বেশি ওভারহেড লাগতে পারে List
ব্যবহারকারী 2313838

একটি বৃহত যথেষ্ট এবং যথাযথ আকারের অবজেক্ট কার্যকরভাবে যাইহোক খণ্ড খণ্ডন মুক্ত।
ডেডএমজি

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

1

আপনি বর্ণিত ডেটা স্ট্রাকচারের ধরণের চারপাশে আমি আমার কোডবেজের (একটি ইসিএস ইঞ্জিন) বেশিরভাগ কেন্দ্রীয় অংশকে ঘুরিয়েছি, যদিও এটি আরও কম সংঘবদ্ধ ব্লক ব্যবহার করে (আরও 4 মেগাবাইটের পরিবর্তে 4 কিলোবাইটের মতো)।

এখানে চিত্র বর্ণনা লিখুন

এটি স্থির-সময় সন্নিবেশগুলি এবং অপসারণের জন্য একটি নিখরচায় ব্লকগুলির জন্য নিখরচায় (একটি ব্লক যা পূর্ণ নয়) এবং সেই ব্লকের সূচকগুলির জন্য ব্লকের ভিতরে একটি উপ-মুক্ত তালিকা অর্জনের জন্য একটি ডাবল ফ্রি তালিকা ব্যবহার করে free সন্নিবেশ উপর পুনরায় দাবি করা প্রস্তুত।

আমি এই কাঠামোর উপকারিতা এবং কভারগুলি কভার করব। আসুন কয়েকটি কনস দিয়ে শুরু করি কারণ তাদের মধ্যে অনেকগুলি রয়েছে:

কনস

  1. এই কাঠামোর জন্য std::vector(একটি খাঁটি কাঠামোগত কাঠামো) চেয়ে কয়েক মিলিয়ন উপাদান সন্নিবেশ করতে প্রায় 4 গুণ বেশি সময় লাগে । এবং আমি মাইক্রো-অপ্টিমাইজেশনে বেশ শালীন কিন্তু সাধারণ ক্ষেত্রে প্রথমে ব্লক ফ্রি তালিকার শীর্ষে ফ্রি ব্লকটি পরিদর্শন করতে হবে, তারপরে ব্লকটি অ্যাক্সেস করতে হবে এবং ব্লকের একটি মুক্ত সূচক পপ করুন concept ফ্রি তালিকাতে, ফ্রি পজিশনে উপাদানটি লিখুন এবং তারপরে ব্লকটি পূর্ণ কিনা তা পরীক্ষা করুন এবং যদি ব্লক ফ্রি তালিকা থেকে ব্লকটি পপ করুন। এটি এখনও একটি ধ্রুবক-সময় অপারেশন তবে পিছনে চাপ দেওয়ার চেয়ে অনেক বড় ধ্রুবক সহ std::vector
  2. সূচিকরণের জন্য অতিরিক্ত গাণিতিক এবং ইন্ডিরিশনের অতিরিক্ত স্তরকে প্রদত্ত এলোমেলোভাবে অ্যাক্সেস প্যাটার্ন ব্যবহার করে উপাদানগুলিতে অ্যাক্সেস করতে প্রায় দ্বিগুণ সময় লাগে।
  3. ক্রমবর্ধমান অ্যাক্সেস একটি আয়রেটর ডিজাইনে দক্ষতার সাথে মানচিত্র তৈরি করে না কারণ প্রতিটি বার যখন এটি বাড়ানো হয় তখন অতিরিক্ত শাখা পরিচালনা করতে হয়।
  4. এটির বেশিরভাগ মেমরি ওভারহেড থাকে, সাধারণত উপাদান প্রতি 1 বিট প্রায়। উপাদান প্রতি 1 বিট খুব বেশি শোনায় না, তবে আপনি যদি এটি ব্যবহার করে এক মিলিয়ন 16-বিট পূর্ণসংখ্যা সংরক্ষণ করতে পারেন তবে এটি একটি নিখুঁত কমপ্যাক্ট অ্যারের চেয়ে 6.25% বেশি মেমরি ব্যবহার। যাইহোক, অনুশীলনে এটি যতটা সংরক্ষণ করে তার অতিরিক্ত ক্ষমতা std::vectorঅপসারণের জন্য কমপ্যাক্ট না করে আপনি তার চেয়ে কম স্মৃতি ব্যবহার করবেন vector। এছাড়াও আমি সাধারণত এ জাতীয় কিশোর উপাদানগুলি সঞ্চয় করতে এটি ব্যবহার করি না।

পেশাদাররা

  1. for_eachক্রিয়াকলাপের অ্যাক্সেস যা কোনও ব্লকের মধ্যে কলব্যাক প্রসেসিং রেঞ্জের উপাদানগুলির সীমাবদ্ধ অ্যাক্সেসের গতিকে প্রায় প্রতিদ্বন্দ্বী করে std::vector(কেবলমাত্র 10% ডিফের মতো), তাই এটি আমার পক্ষে সবচেয়ে কার্য সম্পাদন-সমালোচনামূলক ব্যবহারের ক্ষেত্রে খুব কম দক্ষ নয় ( একটি ইসিএস ইঞ্জিনে ব্যয় করা বেশিরভাগ সময় অনুক্রমিক অ্যাক্সেসে থাকে)।
  2. এটি পুরোপুরি খালি হয়ে গেলে কাঠামোটিকে হ্রাসকারী ব্লকগুলির সাথে মধ্য থেকে ধ্রুবক-সময় অপসারণের অনুমতি দেয়। ফলস্বরূপ এটি প্রয়োজনীয়ভাবে ডেটা স্ট্রাকচারটি উল্লেখযোগ্যভাবে আরও বেশি মেমরি ব্যবহার করে না তা নিশ্চিত করার পক্ষে যথেষ্ট শালীন।
  3. এটি সেই উপাদানগুলিতে সূচকগুলি অকার্যকর করে না যা সরাসরি পাত্রে সরানো হয় না কারণ এটি পরবর্তী সন্নিবেশের পরে এই গর্তগুলি পুনরায় দাবি করার জন্য একটি বিনামূল্যে তালিকা পদ্ধতির সাহায্যে পিছনে গর্ত ফেলে।
  4. স্মৃতিচারণা শেষ হওয়ার বিষয়ে আপনাকে এতটা চিন্তা করতে হবে না এমনকি যদি এই কাঠামোটিতে একটি মহাকাশ সংখ্যক উপাদান রয়েছে তবে এটি কেবল ছোট সংক্ষিপ্ত ব্লকগুলির জন্যই অনুরোধ করে যা বিপুল সংখ্যক অনাবৃত ব্যবহারের সন্ধান করতে ওএসের পক্ষে কোনও চ্যালেঞ্জ তৈরি করে না which পেজ।
  5. এটি পুরো কাঠামোটি লক না করেই একত্রে এবং থ্রেড-সুরক্ষার জন্য নিজেকে ভাল ধার দেয়, যেহেতু অপারেশনগুলি সাধারণত ব্যক্তিগত ব্লকে স্থানীয়করণ করা হয়।

এখন আমার কাছে সবচেয়ে বড় সুবিধাটি হ'ল এই ডেটা কাঠামোর একটি অপরিবর্তনীয় সংস্করণ তৈরি করা তুচ্ছ হয়ে উঠল:

এখানে চিত্র বর্ণনা লিখুন

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

অ-সংযুক্ত অ্যারেতে ক্যাশে লোকেশন নেই যার ফলস্বরূপ খারাপ পারফরম্যান্স হয়। তবে একটি 4 এম ব্লকের আকারে দেখে মনে হচ্ছে ভাল ক্যাশিংয়ের জন্য যথেষ্ট লোকেশন থাকবে।

রেফারেন্সের স্থানীয়তা সেই আকারের ব্লকগুলি নিয়ে নিজেকে উদ্বিগ্ন করার মতো কিছু নয়, কেবল 4 কিলোবাইট ব্লক রেখে দিন। একটি ক্যাশে লাইন সাধারণত 64 বাইট হয়। আপনি যদি ক্যাশে মিসগুলি হ্রাস করতে চান, তবে কেবলমাত্র সেইগুলি ব্লকগুলি সঠিকভাবে সারিবদ্ধ করার দিকে মনোনিবেশ করুন এবং সম্ভব হলে আরও ক্রমবর্ধমান অ্যাক্সেস প্যাটার্নের পক্ষে হন।

একটি এলোমেলো অ্যাক্সেস মেমরি প্যাটার্নকে অনুক্রমিকভাবে রূপান্তরিত করার খুব দ্রুত উপায় হ'ল বিটসেট ব্যবহার করা। ধরা যাক আপনার কাছে সূচকগুলির একটি নৌকা ভার রয়েছে এবং এগুলি এলোমেলোভাবে রয়েছে। আপনি কেবল সেগুলির মাধ্যমে লাঙল করতে পারেন এবং বিটসেটে বিটগুলি চিহ্নিত করতে পারেন। তারপরে আপনি আপনার বিটসেটের মাধ্যমে পুনরাবৃত্তি করতে পারেন এবং কোন বাইটটি শূন্য নয় তা যাচাই করতে পারেন, একবারে 64৪-বিট পরীক্ষা করে দেখুন। একবার আপনি 64৪-বিটের একটি সেটের মুখোমুখি হলেন যার মধ্যে কমপক্ষে একটি বিট সেট হয়ে গেলে আপনি কী বিট সেট আছে তা দ্রুত নির্ধারণ করতে আপনি এফএফএস নির্দেশাবলী ব্যবহার করতে পারেন । বিটগুলি আপনাকে সূচকগুলি ক্রম অনুসারে বাছাই করা ব্যতীত আপনাকে কী সূচকগুলি অ্যাক্সেস করতে হবে তা বলে।

এটির কিছুটা ওভারহেড রয়েছে তবে কিছু ক্ষেত্রে এটি সার্থক বিনিময় হতে পারে, বিশেষত যদি আপনি এই সূচকগুলি বহুবার লুপ করে চলেছেন।

কোনও আইটেম অ্যাক্সেস করা ততটা সহজ নয়, ইন্ডিয়ারেশনের একটি অতিরিক্ত স্তর রয়েছে। এই কি দূরে অপ্টিমাইজড পাবেন? এটি কি ক্যাশে সমস্যা সৃষ্টি করবে?

না, এটি অপ্টিমাইজ করা যায় না। এলোমেলোভাবে অ্যাক্সেস, কমপক্ষে, এই কাঠামোর সাথে সর্বদা বেশি ব্যয় হবে। এটি প্রায়শই আপনার ক্যাশে মিস করে না এমনটা বাড়িয়ে তোলে না যেহেতু আপনি ব্লকগুলিতে পয়েন্টারগুলির অ্যারে দিয়ে উচ্চ সাময়িক লোকাল পাবেন to

যেহেতু 4M সীমা হিট হওয়ার পরে রৈখিক বৃদ্ধি রয়েছে, তাই আপনি সাধারণত আপনার চেয়ে অনেক বেশি বরাদ্দ রাখতে পারেন (বলুন, 1GB মেমরির জন্য সর্বাধিক 250 টি বরাদ্দ)। 4 এম এর পরে কোনও অতিরিক্ত মেমরি অনুলিপি করা হয়নি, তবে আমি নিশ্চিত নই যে অতিরিক্ত বরাদ্দ মেমরির বিশাল অংশগুলি অনুলিপি করার চেয়ে বেশি ব্যয়বহুল।

অনুশীলনে অনুলিপিটি প্রায়শই দ্রুত হয় কারণ এটি বিরল ঘটনা মাত্র একবারের মতো কিছু log(N)/log(2)সময় ঘটে যখন একইসাথে ময়লা সস্তা সাধারণ ক্ষেত্রে সহজ হয় যেখানে আপনি অ্যারেতে কোনও উপাদান পূর্ণ হয়ে যাওয়ার আগে অনেকবার লিখে ফেলতে পারেন এবং আবার পুনঃনির্ধারণের প্রয়োজন হয়। সুতরাং সাধারণত আপনি এই ধরণের কাঠামোর সাথে দ্রুত সন্নিবেশ পাবেন না কারণ সাধারণ কেস কাজটি আরও ব্যয়বহুল হলেও এমনকি যদি বিশাল অ্যারেগুলি পুনর্নির্মাণের ব্যয়বহুল বিরল ক্ষেত্রে এটি মোকাবেলা করতে না হয়।

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

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