কেন বাছাই করা অ্যারে প্রক্রিয়াজাতকরণটি একটি অরসোর্টড অ্যারের চেয়ে ধীর?


233

আমার কাছে 500000 এলোমেলোভাবে উত্পাদিত Tuple<long,long,string>অবজেক্টগুলির একটি তালিকা রয়েছে যার উপর আমি একটি সাধারণ "এর মধ্যে" অনুসন্ধান সম্পাদন করছি:

var data = new List<Tuple<long,long,string>>(500000);
...
var cnt = data.Count(t => t.Item1 <= x && t.Item2 >= x);

যখন আমি আমার এলোমেলো অ্যারে উত্পন্ন করি এবং 100 টি এলোমেলোভাবে উত্পন্ন মানগুলির জন্য অনুসন্ধান চালাই x, অনুসন্ধানগুলি প্রায় চার সেকেন্ডের মধ্যে সম্পূর্ণ হয়। বাছাই করা অনুসন্ধানগুলিতে যে দুর্দান্ত বিস্ময়কর বিষয়গুলি সম্পর্কে জেনে গেছে, তা সত্ত্বেও, আমি আমার 100 অনুসন্ধান চালানোর আগে - প্রথমে Item1, পরে Item2এবং শেষ পর্যন্ত - আমার ডেটা বাছাই করার সিদ্ধান্ত নিয়েছি Item3। আমি শাখার পূর্বাভাসের কারণে বাছাই করা সংস্করণটি একটু দ্রুত সঞ্চালনের প্রত্যাশা করছিলাম: আমার চিন্তাভাবনাটি হ'ল যে একবার আমরা সেই বিন্দুতে পৌঁছে গেলাম, Item1 == xআরও সমস্ত চেকগুলি t.Item1 <= xশাখার সঠিকভাবে "না নেওয়ার" হিসাবে ভবিষ্যদ্বাণী করবে, এর লেজের অংশটি দ্রুত করবে অনুসন্ধান করুন। আমার অবাক করার বিষয়, অনুসন্ধানগুলি বাছাই করা অ্যারেতে দ্বিগুণ সময় নিয়েছিল !

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

কারও কি এই অদ্ভুত প্রভাব সম্পর্কে ভাল ব্যাখ্যা আছে? আমার পরীক্ষার উত্স কোড অনুসরণ করে; আমি নেট নেট ব্যবহার করছি।


private const int TotalCount = 500000;
private const int TotalQueries = 100;
private static long NextLong(Random r) {
    var data = new byte[8];
    r.NextBytes(data);
    return BitConverter.ToInt64(data, 0);
}
private class TupleComparer : IComparer<Tuple<long,long,string>> {
    public int Compare(Tuple<long,long,string> x, Tuple<long,long,string> y) {
        var res = x.Item1.CompareTo(y.Item1);
        if (res != 0) return res;
        res = x.Item2.CompareTo(y.Item2);
        return (res != 0) ? res : String.CompareOrdinal(x.Item3, y.Item3);
    }
}
static void Test(bool doSort) {
    var data = new List<Tuple<long,long,string>>(TotalCount);
    var random = new Random(1000000007);
    var sw = new Stopwatch();
    sw.Start();
    for (var i = 0 ; i != TotalCount ; i++) {
        var a = NextLong(random);
        var b = NextLong(random);
        if (a > b) {
            var tmp = a;
            a = b;
            b = tmp;
        }
        var s = string.Format("{0}-{1}", a, b);
        data.Add(Tuple.Create(a, b, s));
    }
    sw.Stop();
    if (doSort) {
        data.Sort(new TupleComparer());
    }
    Console.WriteLine("Populated in {0}", sw.Elapsed);
    sw.Reset();
    var total = 0L;
    sw.Start();
    for (var i = 0 ; i != TotalQueries ; i++) {
        var x = NextLong(random);
        var cnt = data.Count(t => t.Item1 <= x && t.Item2 >= x);
        total += cnt;
    }
    sw.Stop();
    Console.WriteLine("Found {0} matches in {1} ({2})", total, sw.Elapsed, doSort ? "Sorted" : "Unsorted");
}
static void Main() {
    Test(false);
    Test(true);
    Test(false);
    Test(true);
}

Populated in 00:00:01.3176257
Found 15614281 matches in 00:00:04.2463478 (Unsorted)
Populated in 00:00:01.3345087
Found 15614281 matches in 00:00:08.5393730 (Sorted)
Populated in 00:00:01.3665681
Found 15614281 matches in 00:00:04.1796578 (Unsorted)
Populated in 00:00:01.3326378
Found 15614281 matches in 00:00:08.6027886 (Sorted)

15
শাখার পূর্বাভাসের কারণে: পি
সোনার গনোল

8
@ জালফ আমি শাখার পূর্বাভাসের কারণে বাছাই করা সংস্করণটি কিছুটা দ্রুত সঞ্চালনের আশা করেছি। আমার চিন্তাভাবনাটি হ'ল যে একবার আমরা সেই বিন্দুতে পৌঁছে গেলাম, Item1 == xপরবর্তী সমস্ত চেকগুলি t.Item1 <= xশাখাকে সঠিকভাবে "না নেওয়া" হিসাবে ভবিষ্যদ্বাণী করবে, অনুসন্ধানের লেজের অংশটি দ্রুততর করবে। স্পষ্টতই, চিন্তাভাবনার সেই লাইনটি কঠোর বাস্তবতায় ভুল প্রমাণিত হয়েছে :)
dasblinkenlight

1
@ ক্রিসসিনক্লেয়ার ভাল পর্যবেক্ষণ! আমি আমার উত্তরে একটি ব্যাখ্যা যুক্ত করেছি।
usr ডিরেক্টরির

39
এই প্রশ্নটি এখানে বিদ্যমান প্রশ্নের সদৃশ নয়এক হিসাবে এটি বন্ধ করতে ভোট করবেন না।
চোরমাস্টার

2
@ সর009 মোটেও না! দুটি প্রশ্ন দুটি খুব আলাদা পরিস্থিতি বিবেচনা করে, স্বাভাবিকভাবেই বিভিন্ন ফলাফলের কাছে পৌঁছে।
dasblinkenlight

উত্তর:


269

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

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

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

ক্যাশে থেকে পেনাল্টি মিস করা এই ক্ষেত্রে সংরক্ষিত শাখার পূর্বাভাস জরিমানার তুলনায় বেশি

একটি- structটিপল পরিবর্তন করতে চেষ্টা করুন । এটি কর্মক্ষমতা পুনরুদ্ধার করবে কারণ টিপল সদস্যদের অ্যাক্সেস করার জন্য রানটাইমগুলিতে কোনও পয়েন্টার-ডেরেফারেন্স হওয়ার দরকার নেই।

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

এই জাতীয় আচরণটি দেখায় যে আধুনিক সিপিইউগুলিতে পারফরম্যান্সের পূর্বাভাস দেওয়া কতটা কঠিন। ধারাবাহিক থেকে এলোমেলো মেমরি অ্যাক্সেসে যাওয়ার সময় আমরা কেবলমাত্র 2x ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে পড়ার জন্য স্মৃতি অবিচ্ছিন্নতা লুকানোর জন্য কভারের আওতায় চলেছি তা আমাকে জানান। একটি মেমরি অ্যাক্সেস 50-200 চক্রের জন্য সিপিইউ স্টল করতে পারে। প্রদত্ত এক নম্বরটি এলোমেলো মেমরি অ্যাক্সেসগুলি প্রবর্তন করার সময় প্রোগ্রামটি 10x ধীর হয়ে যাওয়ার আশা করতে পারে।


5
আপনি কেন সি / সি ++ তে শিখেন এমন প্রতিটি কারণেই সি # এর মতো ভাষার ক্ষেত্রে ভারব্যাটিম প্রয়োগ হয় না এর ভাল কারণ!
ব্যবহারকারী541686

37
new List<Tuple<long,long,string>>(500000)নতুন তালিকাটি পরীক্ষার আগে আপনি নিজে নিজে সাজানো তথ্যকে একের পর এক অনুলিপি করে এই আচরণটি নিশ্চিত করতে পারেন । এই দৃশ্যে, বাছাই করা পরীক্ষাটি নিরবচ্ছিন্ন পরীক্ষার মতোই দ্রুত, যা এই উত্তরের যুক্তির সাথে মেলে।
ববসন

3
দুর্দান্ত, আপনাকে অনেক ধন্যবাদ! আমি একটি সমতুল্য Tupleকাঠামো তৈরি করেছি এবং প্রোগ্রামটি আমার পূর্বাভাসের মতো আচরণ শুরু করেছিল: সাজানো সংস্করণটি আরও দ্রুত ছিল। তদতিরিক্ত, নিরবচ্ছিন্ন সংস্করণ দ্বিগুণ দ্রুত হয়ে উঠেছে! সুতরাং এর সাথে সংখ্যাগুলি struct2 টি অমীমাংসিত বনাম 1.9 এর আকার অনুসারে বাছাই করা।
dasblinkenlight

2
তাহলে আমরা কি এ থেকে অনুমান করতে পারি যে শাখা-ভুল ব্যবহারের চেয়ে ক্যাশে-মিস আরও বেশি ব্যথা করে? আমি তাই মনে হয়, এবং সর্বদা তাই চিন্তা। সি ++ এ std::vectorপ্রায় সর্বদা এর চেয়ে ভাল পারফর্ম করে std::list
নওয়াজ

3
@ মেহরদাদ: না, এটি সি ++ এর ক্ষেত্রেও সত্য। এমনকি সি ++ তেও, কমপ্যাক্ট ডেটা স্ট্রাকচারগুলি দ্রুত। C ++ এ অন্য কোনও ভাষার মতো গুরুত্বপূর্ণ ক্যাশে-মিস করা এড়ানো। std::vectorবনাম std::listএকটি ভাল উদাহরণ।
নওয়াজ

4

আপনার তালিকাটি বাছাই করা হয়েছে কিনা তা লিংক জানে না।

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

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


5
আমি মনে করি আপনি এই প্রশ্নটি ভুল বুঝেছেন: অবশ্যই আমি আশা করি না Countবা Whereআমার ডেটা সাজানো হয়েছে এমন ধারণাটি "কোনওভাবে" তুলতে চাই এবং একটি সরল "সমস্ত কিছু পরীক্ষা করুন" অনুসন্ধানের পরিবর্তে একটি বাইনারি অনুসন্ধান চালাব। উন্নত শাখার পূর্বাভাসের কারণে আমি যা কিছু প্রত্যাশা করছিলাম সেটিই ছিল (আমার প্রশ্নের অভ্যন্তরীণ লিঙ্কটি দেখুন), তবে যেমনটি দেখা যাচ্ছে, রেফারেন্স ট্রাম্পের শাখার পূর্বাভাস বড় সময়।
dasblinkenlight
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.