কীভাবে 2 ডি নগর নির্মাতায় ব্যয়বহুল ফাংশনগুলির জন্য কর্মক্ষমতা উন্নত করা যায়


9

আমি ইতিমধ্যে উত্তরগুলির সন্ধান করেছি কিন্তু ব্যয়বহুল ফাংশন / গণনা পরিচালনা করার জন্য আমি সেরা পদ্ধতির সন্ধান করতে সক্ষম হইনি।

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

গতকাল আমি একটি বড় পারফরম্যান্স ইস্যুতে ছুটে এসেছি। নিম্নলিখিত দৃশ্যের দিকে একবার নজর দেওয়া যাক: একজন ব্যবহারকারী অবশ্যই বিল্ডিং এবং রাস্তাগুলি মুছতে পারেন। সুতরাং এখন যদি কোনও ব্যবহারকারী জংশনের ঠিক পরে সংযোগটি ভেঙে দেয় তবে আমাকে একই সাথে অনেকগুলি বিল্ডিং আপডেট করতে হবে । আমি মনে করি প্রথম পরামর্শগুলির মধ্যে একটি হ'ল নেস্টেড লুপগুলি এড়ানো (যা অবশ্যই এই দৃশ্যের একটি বড় কারণ) তবে আমাকে যাচাই করতে হবে ...

  1. যদি কোনও বিল্ডিং এখনও রাস্তার টাইল সরিয়ে ফেলা হয়েছে এমন স্থানে জংশনের সাথে সংযুক্ত থাকে (আমি কেবল এটিই সেই রাস্তা দ্বারা ক্ষতিগ্রস্থ বিল্ডিংয়ের জন্য করি)। (এই পরিস্থিতিতে একটি ছোট সমস্যা হতে পারে)
  2. ব্যাসার্ধ টাইলগুলির তালিকা এবং ব্যাসার্ধের মধ্যে বিল্ডিং পান (নেস্টেড লুপগুলি - বড় সমস্যা!)

    // Go through all buildings affected by erasing this road tile.
    foreach(var affectedBuilding in affectedBuildings) {
        // Get buildings within radius.
        foreach(var radiusTile in affectedBuilding.RadiusTiles) {
            // Get all buildings on Map within this radius (which is technially another foreach).
            var buildingsInRadius = TileMap.Buildings.Where(b => b.TileIndex == radiusTile.TileIndex);  
    
            // Do stuff.
        }
    }

এই সবগুলি আমার এফপিএসকে এক সেকেন্ডের জন্য 60 থেকে প্রায় 10 পর্যন্ত ভেঙে দেয় ।

আমি কি করতে পারে। আমার ধারণাগুলি হবে:

  • এটির জন্য মূল থ্রেড (আপডেট ফাংশন) ব্যবহার না করে অন্য একটি থ্রেড। আমি যখন মাল্টিথ্রেডিং ব্যবহার শুরু করি তখন আমি লক করার সমস্যায় পড়তে পারি।
  • প্রচুর গণনা পরিচালনা করতে একটি সারি ব্যবহার করে (এই ক্ষেত্রে সেরা পন্থাটি কী হবে?)
  • বেশি হিসাব (যেমন ব্যাসার্ধের মধ্যে বিল্ডিং) এড়াতে আমার অবজেক্টগুলিতে (বিল্ডিং) আরও তথ্য রাখুন।

শেষ পন্থাটি ব্যবহার করে আমি পরিবর্তে এই ফোরচকে কোনও নেস্টিং সরিয়ে ফেলতে পারি:

// Go through all buildings affected by erasing this road tile.
foreach(var affectedBuilding in affectedBuildings) {
    // Go through buildings within radius.
    foreach(var buildingInRadius in affectedBuilding.BuildingsInRadius) {
        // Do stuff.
    }
}

তবে আমি জানি না এটি যথেষ্ট কিনা। সিটিস স্কাইলাইনের মতো গেমগুলিতে খেলোয়াড়ের বড় মানচিত্র থাকলে আরও অনেক বেশি বিল্ডিং পরিচালনা করতে হয়। তারা কীভাবে এই জিনিসগুলি পরিচালনা করবে ?! সমস্ত বিল্ডিং একই সময়ে আপডেট হয় না বলে একটি আপডেট করার সারি হতে পারে।

আমি আপনার ধারণা এবং মন্তব্য প্রতীক্ষিত!

অনেক ধন্যবাদ!


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

বিস্তারিত তথ্যের জন্য ধন্যবাদ। আমি নির্ভরতা ধারণা পছন্দ! আমি যে এক তাকান হবে!
ইহেকি

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

আমি আপনাকে এটি দরকারী বলে খুশী: ডি
এক্সাইলা

উত্তর:


3

বিল্ডিং কভারেজ ক্যাশে করা হচ্ছে

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

এটি মেমরির জন্য সিপিইউ চক্রের একটি ক্লাসিক এক্সচেঞ্জ।

অঞ্চল অনুযায়ী কভারেজ তথ্য পরিচালনা করে

যদি এটি সক্রিয় হয়ে যায় আপনি এই তথ্যের উপর নজর রাখতে খুব বেশি স্মৃতি ব্যবহার করছেন, দেখুন আপনি মানচিত্রের অঞ্চলগুলিতে এই জাতীয় তথ্য পরিচালনা করতে পারবেন কিনা। আপনার মানচিত্রটি বর্গাকার অঞ্চলে ভাগ করুনn * এরnটাইলস। যদি কোনও অঞ্চল ফায়ার বিভাগ দ্বারা পুরোপুরি আচ্ছাদিত থাকে তবে সেই অঞ্চলের সমস্ত বিল্ডিংও আচ্ছাদিত। সুতরাং আপনার কেবল অঞ্চল দ্বারা কভারেজ তথ্য সংরক্ষণ করতে হবে, পৃথক বিল্ডিং দ্বারা নয়। যদি কোনও অঞ্চল কেবল আংশিকভাবে আচ্ছাদিত থাকে তবে আপনাকে সেই অঞ্চলে বাই-বিল্ডিং সংযোগগুলি পরিচালনা করতে ফিরে যেতে হবে। সুতরাং আপনার ভবনগুলির আপডেট-ফাংশনটি প্রথমে "" এই বিল্ডিংটি কোনও ফায়ার বিভাগ দ্বারা আচ্ছাদিত অঞ্চলটি কি তা পরীক্ষা করে দেখবে? " এবং যদি না হয় তবে "এই বিল্ডিংটি কি আলাদাভাবে ফায়ার বিভাগ দ্বারা আচ্ছাদিত?" এটি আপডেটগুলির গতিও বাড়ায়, কারণ যখন ফায়ার ডিপার্টমেন্ট সরিয়ে ফেলা হয় তখন আপনাকে 2000 বিল্ডিংয়ের কভারেজ স্টেটগুলি আপডেট করতে হবে না, আপনাকে কেবল 100 টি বিল্ডিং এবং 25 টি অঞ্চল আপডেট করতে হবে।

বিলম্বিত আপডেট

আপনি করতে পারেন এমন আরও একটি অপ্টিমাইজেশন হ'ল তাত্ক্ষণিকভাবে সমস্ত কিছু আপডেট করা এবং একই সাথে সমস্ত কিছু আপডেট করা না।

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

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

মাল্টিথ্রেডিং সম্পর্কিত

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


এটি ব্যাখ্যা করে যে কেন SNES এ সিমসিটি পাওয়ার / পুনরায় সংযোগ স্থাপনের জন্য কিছুটা সময় নেয়, আমি অনুমান করি এটির অন্যান্য ক্ষেত্রের প্রভাবগুলির সাথেও এটি ঘটে।
lozzajp

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

@ ইহেকি এর জন্য সর্বজনীনভাবে প্রয়োগযোগ্য সমাধান নেই, কারণ এটি অত্যন্ত পরিস্থিতি নির্ভর যে কোন গণনাগুলি আপনি বিলম্ব করতে পারেন, যা আপনি পারবেন না এবং গণনার একটি বোধগম্য ইউনিট কী what's
ফিলিপ

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

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

3

1. সদৃশ কাজ

আপনার affectedBuildingsসম্ভবত একে অপরের খুব কাছাকাছি, তাই বিভিন্ন রেডিয়াই ওভারল্যাপ হয়ে যাবে। যে বিল্ডিংগুলিকে আপডেট করা দরকার তা ফ্ল্যাগ করুন, তারপরে সেগুলি আপডেট করুন।

var toBeUpdated = new HashSet<Tiles>();
foreach(var affectedBuilding in affectedBuildings) {
    foreach(var radiusTile in affectedBuilding.RadiusTiles) {
         toBeUpdated.Add(radiusTile);

}
foreach (var tile in toBeUpdated)
{
    var buildingsInTile = TileMap.Buildings.Where(b => b.TileIndex == radiusTile.TileIndex);
    // Do stuff.
}

2. অনুপযুক্ত ডেটাস্ট্রাকচার।

var buildingsInTile = TileMap.Buildings.Where(b => b.TileIndex == radiusTile.TileIndex);

স্পষ্টভাবে হওয়া উচিত

var buildingsInRadius = tile.Buildings;

যেখানে বিল্ডিংগুলি IEnumerableধ্রুব পুনরাবৃত্তির সময় সহ (যেমন ক List<Building>)


ভাল যুক্তি! আমি অনুমান করি যে আমি মোরলিনকিউ ব্যবহার করে একটিতে একটি পৃথক () ব্যবহার করার চেষ্টা করেছি তবে আমি সম্মত যে এটি চেক ডুপ্লিকেটগুলির চেয়ে আরও দ্রুত হতে পারে।
ইয়েকি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.