মাল্টিথ্রেডিং 2 ডি মাধ্যাকর্ষণ গণনা


24

আমি একটি স্পেস এক্সপ্লোরেশন গেম তৈরি করছি এবং আমি বর্তমানে মাধ্যাকর্ষণ নিয়ে কাজ শুরু করেছি (এক্সএনএর সাথে সি # তে)।

মাধ্যাকর্ষণটির এখনও টুইঙ্ক দরকার, তবে আমি এটি করতে পারার আগে, আমার পদার্থবিজ্ঞানের গণনার সাথে কিছু পারফরম্যান্স সম্পর্কিত সমস্যাগুলি সমাধান করা দরকার।

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

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

Gravity.cs

public void Update()
    {
        foreach (KeyValuePair<string, Entity> e in entityEngine.Entities)
        {
            Vector2 Force = new Vector2();

            foreach (KeyValuePair<string, Entity> e2 in entityEngine.Entities)
            {
                if (e2.Key != e.Key)
                {
                    float distance = Vector2.Distance(entityEngine.Entities[e.Key].Position, entityEngine.Entities[e2.Key].Position);
                    if (distance > (entityEngine.Entities[e.Key].Texture.Width / 2 + entityEngine.Entities[e2.Key].Texture.Width / 2))
                    {
                        double angle = Math.Atan2(entityEngine.Entities[e2.Key].Position.Y - entityEngine.Entities[e.Key].Position.Y, entityEngine.Entities[e2.Key].Position.X - entityEngine.Entities[e.Key].Position.X);

                        float mult = 0.1f *
                            (entityEngine.Entities[e.Key].Mass * entityEngine.Entities[e2.Key].Mass) / distance * distance;

                        Vector2 VecForce = new Vector2((float)Math.Cos(angle), (float)Math.Sin(angle));
                        VecForce.Normalize();

                        Force = Vector2.Add(Force, VecForce * mult);
                    }
                }
            }

            entityEngine.Entities[e.Key].Position += Force;
        }

    }

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

অ্যান্টিইঙ্গাইন.সি (গ্রাভিটি.সি এর একটি উদাহরণ পরিচালনা করে)

public class EntityEngine
{
    public Dictionary<string, Entity> Entities = new Dictionary<string, Entity>();
    public Gravity gravity;
    private Thread T;


    public EntityEngine()
    {
        gravity = new Gravity(this);
    }


    public void Update()
    {
        foreach (KeyValuePair<string, Entity> e in Entities)
        {
            Entities[e.Key].Update();
        }

        T = new Thread(new ThreadStart(gravity.Update));
        T.IsBackground = true;
        T.Start();
    }

}

এন্টিইঙ্গাইন গেম 1 সিএস-এ তৈরি করা হয়েছে এবং এর আপডেট () পদ্ধতিটি গেম 1 সিএসের মধ্যে ডাকা হয়।

প্রতিবার গেম আপডেট হওয়ার সাথে সাথে পৃথক থ্রেডে চালানোর জন্য আমার গ্রাভিটি.সি.তে আমার পদার্থবিজ্ঞানের গণনা প্রয়োজন, যাতে গণনাটি গেমটি ভয়াবহভাবে কম (0-2) এফপিএসে নামিয়ে না দেয়।

আমি এই থ্রেডিংয়ের কাজটি করা সম্পর্কে কীভাবে যাব? (উন্নত প্ল্যানেটরি গ্র্যাভিটি সিস্টেমের জন্য যে কোনও পরামর্শই যদি কারও কাছে থাকে তবে তা স্বাগত জানানো হবে)

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

সাহায্যের জন্য আপনাকে ধন্যবাদ!

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


এটি [উপরে বর্ণিত আপনার আপডেট থ্রেডিং সিস্টেম] এখন কী করে (এটি কাজ করে)? বিটিডব্লিউ আমি এটিকে খেলা চক্রে ASAP শুরু করেছিলাম - যেমন সত্তাগুলি আপডেট হওয়ার আগে।
ThorinII

2
আপনার নেস্টেড লুপগুলির অভ্যন্তরে ট্রিগ কলগুলি সম্ভবত সবচেয়ে বড় হিট। আপনি যদি এগুলি মুছে ফেলার কোনও উপায় খুঁজে kপান তবে এই O(n^2)সমস্যার সমাধান অনেকটা কমে যাবে ।
আরবেরি ইয়ং

1
প্রকৃতপক্ষে ট্রিগ কলগুলি সম্পূর্ণ অপ্রয়োজনীয় : আপনি প্রথমে কোনও ভেক্টর থেকে একটি কোণ গণনা করুন, তারপরে অন্য কোনও ভেক্টর তৈরি করতে এটি ব্যবহার করুন যা প্রদত্ত দিক নির্দেশ করে। তারপরে আপনি সেই ভেক্টরটিকে স্বাভাবিক করুন, তবে যেহেতু sin² + cos² ≡ 1এটি ইতিমধ্যে স্বাভাবিক হয়ে গেছে! আপনি কেবল আসল ভেক্টরটি ব্যবহার করতে পারতেন যা আপনার আগ্রহী দুটি বিষয়কে সংযুক্ত করে এবং এটিকে স্বাভাবিক করে তুলেছে। কোন ট্রিগ কল প্রয়োজন নেই।
বাম দিকের বাইরে

এক্সএনএ অবচয় হয় না?
jcora

@ অন্নবনে এই প্রশ্নটি আলোচনায় সহায়ক কিছু যুক্ত করে না। এবং না, এক্সএনএ-এর স্থিতি হ্রাসের কোনও সংজ্ঞায় ফিট করে না।
শেঠ ব্যাটিন

উত্তর:


36

আপনার এখানে যা আছে তা ক্লাসিক ও (n²) অ্যালগরিদম। আপনার সমস্যার মূল কারণটি থ্রেডিংয়ের সাথে কিছুই করার নেই এবং আপনার অ্যালগরিদমের উচ্চতর জটিলতা রয়েছে তা দিয়ে সবকিছু করার দরকার নেই।

যদি আপনি এর আগে "বিগ ও" স্বরলিপিটি না পেয়ে থাকেন তবে এর মূল অর্থ এন উপাদানগুলির উপর কাজ করার জন্য প্রয়োজনীয় অপারেশনগুলির সংখ্যা (এটি অতি-সরল ব্যাখ্যা)। আপনার 100 টি উপাদান আপনার লুপের অভ্যন্তরীণ অংশটি 10000 বার সম্পাদন করছে ।

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

যদি প্রতিটি সত্তা প্রতিটি অন্য সত্তাকে প্রভাবিত করে, তবে আপনার প্রয়োজন অনুসারে একটি ও (এন) অ্যালগরিদম প্রয়োজন। তবে দেখে মনে হচ্ছে যে কয়েকটি সংস্থাই আসলে ইন্টারঅ্যাক্ট করছে (কারণে if (distance < ...)) - যাতে আপনি " স্পেসিয়াল পার্টিশন " নামে কিছু ব্যবহার করে আপনার ক্রিয়াকলাপের সংখ্যা উল্লেখযোগ্যভাবে হ্রাস করতে পারেন ।

যেহেতু এটি মোটামুটি বিস্তারিত বিষয় এবং কিছুটা খেলা-নির্দিষ্ট, তাই আপনাকে আরও বিশদের জন্য একটি নতুন প্রশ্ন জিজ্ঞাসা করার পরামর্শ দিচ্ছি। চল এগোই...


আপনার কোডগুলির সাথে একটি প্রধান পারফরম্যান্স সমস্যা মোটামুটি সহজ। এটি ধীরে ধীরে কমছে :

foreach (KeyValuePair<string, Entity> e in Entities)
{
    Entities[e.Key].Update();
}

আপনি ইতিমধ্যে আপনার কাছে থাকা কোনও বস্তুর জন্য স্ট্রিং দিয়ে প্রতিটি অভিধান (আপনার অন্যান্য লুপগুলিতে একাধিকবার) স্ট্রিংয়ের সাহায্যে অনুসন্ধান করছেন !

আপনি এটি করতে পারেন:

foreach (KeyValuePair<string, Entity> e in Entities)
{
    e.Value.Update();
}

অথবা আপনি এটি করতে পারেন: (আমি ব্যক্তিগতভাবে এটি আরও ভাল পছন্দ করি, উভয়েরই একই গতি হওয়া উচিত)

foreach (Entity e in Entities.Values)
{
    e.Update();
}

স্ট্রিং অনুসারে অভিধানের অনুসন্ধান বেশ ধীর। সরাসরি আইট্রেট করা উল্লেখযোগ্যভাবে দ্রুত হবে।

যদিও, আপনি কত ঘন ঘন না আসলে নামে আইটেম সন্ধান করতে হবে? এই সমস্তগুলির মাধ্যমে আপনার কতবার পুনরাবৃত্তি করতে হবে তার তুলনায়? যদি আপনি কেবল নাম সন্ধান করেন খুব কমই, আপনার সত্তাগুলি একটিতে List(তাদের একটি Nameসদস্য দিন) সংরক্ষণ করার কথা বিবেচনা করুন ।

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

সম্পাদনা: পরবর্তী বৃহত্তম সমস্যাটি সম্ভবত কল করা Atan2এবং তারপরে তাৎক্ষণিকভাবে এটিকে আবার ভেক্টরে রূপান্তরিত করা Sinএবং এর সাথে Cos! কেবল ভেক্টর সরাসরি ব্যবহার করুন।


অবশেষে, আসুন থ্রেডিং এবং আপনার কোডের প্রধান সমস্যাগুলি সম্বোধন করুন:

প্রথম এবং সর্বাধিক স্পষ্ট: প্রতি ফ্রেমে একটি নতুন থ্রেড তৈরি করবেন না! থ্রেড অবজেক্টস বেশ "ভারী"। এর সহজ সমাধানটি কেবল ThreadPoolপরিবর্তে ব্যবহার করা হবে।

অবশ্যই, এটি এত সহজ নয়। দ্বিতীয় নম্বর সমস্যার দিকে এগিয়ে চলুন: একবারে দুটি থ্রেডে ডেটা স্পর্শ করবেন না! (উপযুক্ত থ্রেড-সুরক্ষা অবকাঠামো যোগ না করেই))

আপনি এখানে মূলত সর্বাধিক ভয়াবহ উপায়ে স্টেম্পিং করছেন । এখানে কোনও থ্রেড-সুরক্ষা নেই। gravity.Updateআপনি যে একাধিক " " থ্রেড শুরু করছেন তা অপ্রত্যাশিত সময়ে অন্য থ্রেডে ব্যবহৃত ডেটা ওভাররাইট করা যেতে পারে। ইতিমধ্যে আপনার মূল থ্রেডটি এই সমস্ত ডেটা স্ট্রাকচারকেও স্পর্শ করবে। যদি এই কোডটি মেমরি অ্যাক্সেস লঙ্ঘনের কঠোরভাবে পুনরুত্পাদন করে তবে আমি অবাক হব না।

এই থ্রেডের মতো নিরাপদ কিছু করা শক্ত এবং এটি ওভারহেডে উল্লেখযোগ্য পারফরম্যান্স যুক্ত করতে পারে যে এটি প্রায়শই চেষ্টা করা উপযুক্ত নয়।


তবে, যাইহোক আপনি কীভাবে এটি করবেন সে সম্পর্কে সুন্দরভাবে জিজ্ঞাসা করার মতো (তাই নয়) দেখে আসুন সেই বিষয়ে ...

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

আপনার সমস্যার মূলত তিনটি পদ্ধতি রয়েছে:

1) আপনি থ্রেড জুড়ে ব্যবহার করেন এমন সমস্ত ডেটার চারদিকে লক রাখুন । সি # তে এটি lockবিবৃতি দিয়ে মোটামুটি সহজ করা হয়েছে।

সাধারণত আপনি new objectকিছু সেট ডেটা সুরক্ষিত করার জন্য লক করার জন্য একটি বিশেষভাবে তৈরি (এবং ধরে রাখুন!) তৈরি করেন ( এটি সুরক্ষার কারণে যা সাধারণত পাবলিক এপিআইগুলি লেখার সময় আসে - তবে ভাল স্টাইলটি একই রকম)। এর পরে আপনি আপনার লক বস্তু লক আবশ্যক সর্বত্র আপনি ডাটা এটা রক্ষা করে অ্যাক্সেস!

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

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

2) থ্রেডে ডেটা অনুলিপি করুন, এটি প্রক্রিয়া করতে দিন এবং তারপরে ফলাফলটি শেষ হয়ে গেলে আবার বের করুন।

আপনি কীভাবে বাস্তবায়ন করছেন তা নির্ভর করে আপনি যা করছেন তার উপর নির্ভর করবে। তবে স্পষ্টতই এটি একটি সম্ভাব্য ব্যয়বহুল অনুলিপি অপারেশনকে জড়িত করবে (বা দুটি) যে অনেক ক্ষেত্রে কেবল একক থ্রেডযুক্ত কাজগুলি করার চেয়ে ধীর হবে।

এবং, অবশ্যই, আপনার এখনও পটভূমিতে অন্য কিছু কাজ করতে হবে, অন্যথায় আপনার মূল থ্রেডটি কেবল আপনার অন্যান্য থ্রেডটি শেষ হওয়ার অপেক্ষায় বসে থাকবে যাতে এটি ডেটাটি অনুলিপি করতে পারে!

3) থ্রেড-নিরাপদ ডেটা স্ট্রাকচার ব্যবহার করুন।

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


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


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

থ্রেডিং ম্যাজিকালি আপনার যে কোনও দ্রুত কোডটি দিবে না - এটি আপনাকে একই সাথে অন্য কিছু করতে দেয়!


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

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

1
আপনি স্বাগত, খুশি এটি সাহায্য করেছে :) আপনি যখন আপনার নতুন প্রশ্ন পোস্ট করেন, দয়া করে এখানে একটি লিঙ্ক ফেলে দিন যাতে আমি এবং অন্য যে কেউ অনুসরণ করে, এটি দেখতে পাবে।
অ্যান্ড্রু রাসেল

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

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

22

ঠিক আছে প্রথম নজরে কিছু জিনিস আপনার ব্যবহার করা উচিত। প্রথমে আপনার সংঘর্ষের চেকগুলি হ্রাস করার চেষ্টা করা উচিত, আপনি চতুষ্কোণের মতো কিছু জাতীয় স্থান ব্যবহার করে এটি করতে পারেন । এটি আপনাকে দ্বিতীয় পূর্বাভাসের গণনা হ্রাস করতে দেয়, কারণ আপনি কেবল সত্ত্বাগুলি প্রথমটিকে বন্ধ করে দিবেন query

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

আরেকটি বিষয় হ'ল ফোরচ লুপে আপনার করণীয় নেই entityEngine.Entities[e.Key].Textureকারণ আপনি ইতিমধ্যে আপনার ফোরচ শিরোনামে ডিকটি অ্যাক্সেস করেছেন। পরিবর্তে আপনি কেবল লিখতে পারেন e.Texture। আমি এর প্রভাব সম্পর্কে সত্যিই জানতে পারি না, কেবল আপনাকে জানাতে চেয়েছিলাম;)

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

এ এবং বি 2 সত্তার উদাহরণ সহ:

pick A in first foreach loop
   pick A in second foreach loop
      skip A because keys are the same
   pick B in second foreach loop
      collision stuff
pick B in first foreach loop
   pick A in second foreach loop
      collision stuff
   pick B in second foreach loop
      skip B because keys are the same

যদিও এটি একটি সম্ভাব্য পন্থা, সম্ভবত আপনি এক এবং A কে বিপরীতে পরিচালনা করতে পারেন, আপনার সংঘর্ষের চেকের অর্ধেকটি এড়িয়ে যেতে পারেন

আশা করি এটি আপনার শুরু হবে =)

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

EDIT1: QuadTree টিউটোরিয়াল সঙ্গে লিংক (জাভা): http://gamedev.tutsplus.com/tutorials/implementation/quick-tip-use-quadtrees-to-detect-likely-collisions-in-2d-space/


10
মাধ্যাকর্ষণ অনুকরণের জন্য চতুর্ভুজ / অষ্টমীজ ব্যবহার সম্পর্কে দুর্দান্ত জিনিসটি হ'ল দূরবর্তী কণাগুলি উপেক্ষা করার পরিবর্তে আপনি আপনার গাছের প্রতিটি শাখায় মোট ভর এবং সমস্ত কণার ভর কেন্দ্র সংরক্ষণ করতে পারেন এবং এটি গড় মাধ্যাকর্ষণ প্রভাব গণনা করতে ব্যবহার করতে পারেন অন্যান্য, দূরবর্তী কণায় এই শাখার সমস্ত কণা of এটি বার্নস-হাট অ্যালগরিদম হিসাবে পরিচিত এবং এটি পেশাদাররা ব্যবহার করে
ইলমারি করোনেন

10

সত্য, প্রথম জিনিসটি আপনার করা উচিত আরও ভাল অ্যালগরিদমে স্যুইচ করা।

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

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

যাইহোক, অন্যান্য উত্তরগুলি যেমন উল্লেখ করেছে, বিপুল সংখ্যক ইন্টারেক্টিভ কণাগুলি দক্ষতার সাথে সিমুলেট করার সাধারণ কৌশলটি তাদের একটি চতুর্ভুজ (2 ডি তে) বা একটি অষ্ট্রি (3 ডি) তে সাজানো। বিশেষত, মাধ্যাকর্ষণ অনুকরণের জন্য, আপনি যে মৌলিক অ্যালগরিদমটি ব্যবহার করতে চান তা হ'ল বার্নেস ut হাট সিমুলেশন অ্যালগরিদম , যেখানে আপনি আপনার কোয়াড / অষ্টমীর প্রতিটি কোষে থাকা সমস্ত কণার মোট ভর (এবং ভর কেন্দ্রে) সংরক্ষণ করেন এবং অন্যান্য কোষের দূরবর্তী কণায় সেই ঘরের কণাগুলির গড় মাধ্যাকর্ষণ প্রভাব আনুমানিকভাবে ব্যবহার করুন use

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


6

আর একটি অপ্টিমাইজেশান উত্তর যা থ্রেডের সাথে কিছুই করার নেই। এর জন্যে দুঃখিত.

আপনি প্রতিটি জুটির দূরত্ব () গণনা করছেন। এটি একটি বর্গক্ষেত্র গ্রহণ জড়িত, যা ধীর। এটি প্রকৃত আকার পেতে বেশ কয়েকটি অবজেক্ট লুকআপ জড়িত।

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

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


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

আসলে এটি একটি খুব ভাল পয়েন্ট। আমি এটিকে সংঘর্ষের পরীক্ষা হিসাবে ভুলভাবে লিখছি, তবে এটি আসলে বিপরীতে করছে: কণাগুলি যদি স্পর্শ না করে তবে একে অপরকে প্রভাবিত করে।
এলিস্টায়ার বুকসটন

3

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

i = 0; i < count; i++
  j = 0; j < count; j++

  object_i += force(object_j);

এই

i = 0; i < count-1; i++
  j = i+1; j < count; j++

  object_i += force(object_j);
  object_j += force(object_i);

সাহায্য করতে পারত


1
কেন যে সাহায্য করবে?

1
কারণ প্রথম দুটি লুপগুলি 10 000 পুনরাবৃত্তি করে তবে দ্বিতীয় লুপগুলি কেবল 4 950 পুনরাবৃত্তি করে।
বুক্সি

1

আপনার যদি ইতিমধ্যে 10 টি সিমুলেটেড অবজেক্টের সাথে এ জাতীয় বিশাল সমস্যা থাকে তবে আপনাকে কোডটি অনুকূলিত করতে হবে! আপনার নেস্টেড লুপটি কেবল 10 * 10 টি পুনরাবৃত্তি ঘটায় যার মধ্যে 10 টি পুনরাবৃত্তি বাদ দেওয়া হয় (একই বস্তু), যার ফলে অভ্যন্তরীণ লুপের 90 পুনরাবৃত্তি ঘটে। আপনি যদি কেবল ২ টি এফপিএস অর্জন করেন তবে এর অর্থ হ'ল আপনার পারফরম্যান্সটি এতটাই খারাপ, যে আপনি কেবলমাত্র প্রতি সেকেন্ডে অভ্যন্তরীণ লুপের 180 টি পুনরাবৃত্তি অর্জন করতে পারেন।

আমি আপনাকে নিম্নলিখিতটি করার পরামর্শ দিচ্ছি:

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

  2. অপ্টিমাইজেশনস: আপনি ও (N²) প্রচেষ্টা সমস্যা সম্পর্কে অনেক কিছু করতে পারবেন না (অর্থাত: সিমুলেটেড অবজেক্ট N এর সংখ্যার সাথে গণনার সময় চতুর্ভুজ বৃদ্ধি পায়), আপনি কোডটি নিজেই উন্নত করতে পারেন।

    ক) আপনি আপনার কোডের মধ্যে প্রচুর "এসোসিয়েটিভ অ্যারে" (অভিধান) লকআপ ব্যবহার করেন। এগুলি ধীর! উদাহরণস্বরূপ entityEngine.Entities[e.Key].Position। আপনি কি শুধু ব্যবহার করতে পারবেন না e.Value.Position? এটি একটি চেহারা সংরক্ষণ করে। আপনি ই এবং ই 2 দ্বারা রেফারেন্স করা সামগ্রীর বৈশিষ্ট্যগুলিকে অ্যাক্সেস করার জন্য পুরো অভ্যন্তরীণ লুপে সর্বত্র এটি করেন ... এটি পরিবর্তন করুন! খ) আপনি লুপের ভিতরে একটি নতুন ভেক্টর তৈরি করেন লুপেরnew Vector2( .... ) । সমস্ত "নতুন" কলগুলি কিছু মেমরি বরাদ্দ জড়িত (এবং পরে: অবনতি)। এগুলি ডিকোরিয়ানের দেখার চেয়ে অনেক ধীর। আপনার যদি কেবলমাত্র এই ভেক্টরকে অস্থায়ীভাবে প্রয়োজন হয়, সুতরাং এটিগুলি লুপগুলির বাইরে বরাদ্দ করুন এবং পুনরায় ব্যবহার করুন - নতুন মান তৈরি করার পরিবর্তে এর মানগুলিকে নতুন মানগুলিতে পুনরায় নতুন করে তৈরি করুন। গ) আপনি প্রচুর ত্রিকোণমিতিক ফাংশন ব্যবহার করেন (যেমন atan2এবংcos) লুপের মধ্যে। যদি আপনার নির্ভুলতার সত্যই সত্যিকারের প্রয়োজন না হয় তবে আপনি পরিবর্তে একটি সারণী ব্যবহার করার চেষ্টা করতে পারেন। এটি করার জন্য আপনি নিজের মানটিকে একটি সংজ্ঞায়িত পরিসীমাতে স্কেল করুন, এটি একটি পূর্ণসংখ্যার মানকে গোল করুন এবং প্রাক-গণনা করা ফলাফলগুলির একটি সারণীতে এটি সন্ধান করুন। যদি আপনার এটির সাহায্যের প্রয়োজন হয় তবে কেবল জিজ্ঞাসা করুন। d) আপনি প্রায়শই ব্যবহার করেন .Texture.Width / 2। আপনি .Texture.HalfWidthএটির প্রাক-গণনা করতে পারেন এবং ফলাফলটি বা- হিসাবে এটি সর্বদা একটি ইতিবাচক পূর্ণসংখ্যার মান হিসাবে সংরক্ষণ করতে পারেন - আপনি শিফট ক্রিয়াকলাপটিকে >> 1বিভাজনে দুটি দ্বারা বিভক্ত করতে পারেন ।

একবারে কেবল একটি পরিবর্তন করুন এবং মানদণ্ড দ্বারা পরিবর্তনটি পরিমাপ করুন এটি কীভাবে আপনার রানটাইমকে প্রভাবিত করেছে! অন্য জিনিসটি খারাপ হওয়ার সময় একটি জিনিস হয়তো ভাল (এমনকি আমি তাদের উপরে প্রস্তাবও দিয়েছিলাম!) ...

আমি মনে করি এই অপ্টিমাইজেশানগুলি একাধিক থ্রেড ব্যবহার করে আরও ভাল পারফরম্যান্স অর্জনের চেষ্টা করার চেয়ে অনেক ভাল হবে! থ্রেডগুলি সমন্বয় করতে আপনার অনেক সমস্যা হবে, সুতরাং তারা অন্য মানগুলি ওভাররাইট করবে না। এছাড়াও অনুরূপ মেমরি অঞ্চলগুলিতে অ্যাক্সেস করার সময় তারা বিরোধ করবে will আপনি যদি এই কাজের জন্য 4 সিপিইউ / থ্রেড ব্যবহার করেন তবে ফ্রেম রেটের জন্য আপনি কেবল 2 থেকে 3 গতি বাড়িয়ে আশা করতে পারেন।


0

আপনি কি অবজেক্ট তৈরির লাইন ছাড়া এটি পুনরায় কাজ করতে সক্ষম?

ভেক্টর 2 ফোর্স = নতুন ভেক্টর 2 ();

ভেক্টর 2 ভেকফোরস = নতুন ভেক্টর 2 ((ভাসমান) ম্যাথ.কোস (কোণ), (ভাসা) ম্যাথ.সিন (কোণ));

যদি আপনি প্রতিবার দুটি নতুন বস্তু তৈরির পরিবর্তে সত্তার মধ্যে বলের মান স্থাপন করতে পারেন, তবে এটি কার্য সম্পাদনকে উন্নত করতে সহায়তা করতে পারে।


4
Vector2এক্সএনএতে একটি মান ধরণ । এটির কোনও জিসি ওভারহেড নেই এবং নির্মাণের ওভারহেডটি নগন্য। এটি সমস্যার উত্স নয়।
অ্যান্ড্রু রাসেল

@ অ্যান্ড্রু রাসেল: আমি তেমন নিশ্চিত নই, তবে আপনি যদি "নতুন ভেক্টর 2" ব্যবহার করেন তবে বাস্তবে এখনও তা ঘটবে? আপনি যদি "নতুন" ব্যতীত ভেক্টর 2 (....) ব্যবহার করেন তবে এটি সম্ভবত আলাদা।
SDwarfs

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