অ্যারে বনাম তালিকার পারফরম্যান্স


192

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

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

আসলে কেউ কি এটি পরিমাপ করেছিল? একটি তালিকা মাধ্যমে 6M বার পুনরাবৃত্তি একটি অ্যারের হিসাবে একই সময় নিতে হবে?


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

2
T[]বনাম। List<T>একটি বড় পারফরম্যান্স পার্থক্য করতে পারে। তালিকা থেকে .NET 4.0 এ অ্যারেতে স্থানান্তরিত করার জন্য আমি একটি অত্যন্ত (নেস্টেড) লুপ নিবিড় অ্যাপ্লিকেশনটি অনুকূলিত করেছি। আমি সম্ভবত 5% থেকে 10% উন্নতির প্রত্যাশা করছিলাম তবে 40% এরও বেশি স্পিডআপ! তালিকা থেকে অ্যারেতে সরাসরি সরানো ছাড়া অন্য কোনও পরিবর্তন নেই। সমস্ত গণনা foreachবিবৃতি দিয়ে করা হয়েছিল । মার্ক Gravell এর উত্তর উপর ভিত্তি করে, এটা দেখে মনে হচ্ছে foreachসঙ্গে List<T>বিশেষ করে খারাপ।
বিশেষ সস

উত্তর:


221

পরিমাপ করা খুব সহজ ...

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

অবশ্যই, এটি কেবল তখনই প্রযোজ্য যদি আপনি সমস্ত ডেটা পড়ছেন; কী-ভিত্তিক লকআপগুলির জন্য একটি অভিধান দ্রুত হবে।

"ইনট" ব্যবহার করে আমার ফলাফলগুলি এখানে রয়েছে (দ্বিতীয় নম্বরটি তারা সবাই একই কাজ করেছে যাচাই করার জন্য একটি চেকসাম):

(বাগ ঠিক করতে সম্পাদিত)

List/for: 1971ms (589725196)
Array/for: 1864ms (589725196)
List/foreach: 3054ms (589725196)
Array/foreach: 1860ms (589725196)

পরীক্ষার ছদ্মবেশের উপর ভিত্তি করে:

using System;
using System.Collections.Generic;
using System.Diagnostics;
static class Program
{
    static void Main()
    {
        List<int> list = new List<int>(6000000);
        Random rand = new Random(12345);
        for (int i = 0; i < 6000000; i++)
        {
            list.Add(rand.Next(5000));
        }
        int[] arr = list.ToArray();

        int chk = 0;
        Stopwatch watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 100; rpt++)
        {
            int len = list.Count;
            for (int i = 0; i < len; i++)
            {
                chk += list[i];
            }
        }
        watch.Stop();
        Console.WriteLine("List/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk);

        chk = 0;
        watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 100; rpt++)
        {
            for (int i = 0; i < arr.Length; i++)
            {
                chk += arr[i];
            }
        }
        watch.Stop();
        Console.WriteLine("Array/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk);

        chk = 0;
        watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 100; rpt++)
        {
            foreach (int i in list)
            {
                chk += i;
            }
        }
        watch.Stop();
        Console.WriteLine("List/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk);

        chk = 0;
        watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 100; rpt++)
        {
            foreach (int i in arr)
            {
                chk += i;
            }
        }
        watch.Stop();
        Console.WriteLine("Array/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk);

        Console.ReadLine();
    }
}

8
আকর্ষণীয় বিশদ: এখানে আমার রিগের রিলিজ / ডিইবিইউগির সময়গুলি (.NET 3.5 এসপি 1): 0.92, 0.80, 0.96, 0.93; যা আমাকে জানিয়েছে যে ভিএম-তে আরও কিছু বুদ্ধি রয়েছে যাতে অ্যারে / লুপের জন্য অন্যান্য ক্ষেত্রেগুলির তুলনায় প্রায় 10% ভাল optim
ডেভিড স্মিট

2
হ্যাঁ, অ্যারে / ফর জন্য জেআইটি অপ্টিমাইজেশন রয়েছে। আসলে, আমি এই ধারণার মধ্যে ছিলাম যে এটি দৈর্ঘ্যের কেস অন্তর্ভুক্ত করেছে (যেহেতু এটি জানেন এটি স্থির), সুতরাং কেন আমি প্রথমে এটিকে টানতে পারি নি (যেখানে লিস্ট করেছি সেখানে তার বিপরীতে)। আপডেটের জন্য ধন্যবাদ.
মার্ক Gravell

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

1
প্রতিটি পরীক্ষার জন্য chk এর জন্য পৃথক পরিবর্তনশীল (chk1, chk2, chk3, chk4) ব্যবহার করা হলে আমি নাটকীয়ভাবে আলাদা ফলাফল পেয়েছি। তালিকা / জন্য = 1303ms, অ্যারে / for = 433ms। কোন ধারণা কেন?
জন

4
জন স্কিটির ব্লগে জোন দ্বারা উপরের মন্তব্যে উল্লিখিত লিঙ্কটি নষ্ট হয়ে গেছে। নীচে আপডেট লিংক আছে। কোডব্লগ.জোনসকেট.ুক
জোশ দেলং

88

সারসংক্ষেপ:

  • অ্যারে ব্যবহার করা প্রয়োজন:

    • তাই প্রায়শই সম্ভব। এটি দ্রুত এবং একই পরিমাণ তথ্যের জন্য সবচেয়ে ক্ষুদ্রতম র‌্যাম পরিসীমা নেয়।
    • আপনি যদি কোষের প্রয়োজনীয় গণনা জানেন
    • যদি অ্যারে <85000 বিতে ডেটা সংরক্ষণ করা হয় (পূর্ণসংখ্যার ডেটার জন্য 85000/32 = 2656 উপাদান)
    • উচ্চ র্যান্ডম অ্যাক্সেস গতি প্রয়োজন হলে
  • তালিকাটি ব্যবহারের প্রয়োজন:

    • তালিকার শেষে কোষগুলি যুক্ত করার প্রয়োজন হলে (প্রায়শই)
    • তালিকার প্রারম্ভিক / মাঝখানে কক্ষগুলি যুক্ত করার প্রয়োজন হলে (বন্ধ নয়)
    • যদি অ্যারে <85000 বিতে ডেটা সংরক্ষণ করা হয় (পূর্ণসংখ্যার ডেটার জন্য 85000/32 = 2656 উপাদান)
    • উচ্চ র্যান্ডম অ্যাক্সেস গতি প্রয়োজন হলে
  • লিঙ্কডলিস্ট ব্যবহার করা প্রয়োজন:

    • তালিকার শুরুতে / মাঝামাঝি / শেষে কক্ষগুলি যুক্ত করার প্রয়োজন হলে (প্রায়শই)
    • প্রয়োজন হলে কেবল ক্রমিক অ্যাক্সেস (এগিয়ে / পিছিয়ে)
    • আপনার যদি বড় আইটেম সংরক্ষণ করতে হয় তবে আইটেমের গণনা কম।
    • লিঙ্কগুলির জন্য অতিরিক্ত মেমরি ব্যবহার করার কারণে এটি প্রচুর পরিমাণে আইটেমের জন্য ব্যবহার না করা ভাল।

আরো বিস্তারিত:

রঙ অর্থ

অ্যারে বনাম তালিকা বনাম লিঙ্কযুক্ত তালিকা

আরও বিস্তারিত:

https://stackoverflow.com/a/29263914/4423545


আমি আপনার দাবিতে কিছুটা বিভ্রান্ত হয়ে পড়েছি যে তালিকার প্রিপেন্ড তুলনামূলকভাবে দ্রুত তবে সন্নিবেশ ধীরে ধীরে। সন্নিবেশটিও লিনিয়ার সময়, এবং প্রেন্ডেন্ডের তুলনায় গড়ে 50% বেশি দ্রুত।
মাইক মেরিনোভস্কি

1
সি # তালিকায় মাইকমারিণোস্কি অ্যারে প্রায় মোড়ক। সুতরাং তালিকাভুক্তকরণ সন্নিবেশ ক্ষেত্রে আপনি কেবলমাত্র এক পর্যায়ে রৈখিক সময় পাবেন। এই সিস্টেমের পরে নতুন একটি বড় অ্যারে তৈরি হবে এবং পুরানো থেকে আইটেম অনুলিপি করতে সময় প্রয়োজন হবে।
অ্যান্ড্রু

প্রিপেন্ডস সহ একই জিনিস।
মাইক মেরিভনস্কি

একটি প্রিপেন্ড অপারেশন হল 0 এ কেবল একটি সন্নিবেশ performance
মাইক মেরিনোভস্কি

সন্নিবেশ এবং প্রিপেন্ড উভয়ই হ'ল ও (এন) (মোড়িত)। একটি প্রিপেন্ড হ'ল একটি সন্নিবেশ, তবে এটি স্লো সম্ভবতম সন্নিবেশ কারণ এটি তালিকার সমস্ত আইটেমকে এক স্পট উপরে স্থানান্তর করতে হবে। একটি এলোমেলো স্থানে সন্নিবেশ করতে কেবল সন্নিবেশ বিন্দু থেকে উচ্চতর সূচীতে আইটেমগুলি সরিয়ে নিতে হয়, সুতরাং আইটেমগুলির গড়পড়তা 50% থাকে।
মাইক মেরিনোভস্কি

26

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

ধরুন আপনার ধারণক্ষমতা 10 এর সাথে একটি তালিকা রয়েছে, আপনি একবার 11 তম উপাদান যুক্ত করতে চাইলে তালিকাটি তার ক্ষমতা বাড়িয়ে তুলবে। আপনি ধারণের আইটেমের সংখ্যার তালিকার সক্ষমতা শুরু করে পারফরম্যান্স প্রভাব হ্রাস করতে পারেন।

তবে, যদি কোনও তালিকার মাধ্যমে পুনরাবৃত্তি কোনও অ্যারের উপরে পুনরুক্তি করা তত দ্রুত হয় তবে এটি কেন নির্ধারণ করবেন না?

int numberOfElements = 6000000;

List<int> theList = new List<int> (numberOfElements);
int[] theArray = new int[numberOfElements];

for( int i = 0; i < numberOfElements; i++ )
{
    theList.Add (i);
    theArray[i] = i;
}

Stopwatch chrono = new Stopwatch ();

chrono.Start ();

int j;

 for( int i = 0; i < numberOfElements; i++ )
 {
     j = theList[i];
 }

 chrono.Stop ();
 Console.WriteLine (String.Format("iterating the List took {0} msec", chrono.ElapsedMilliseconds));

 chrono.Reset();

 chrono.Start();

 for( int i = 0; i < numberOfElements; i++ )
 {
     j = theArray[i];
 }

 chrono.Stop ();
 Console.WriteLine (String.Format("iterating the array took {0} msec", chrono.ElapsedMilliseconds));

 Console.ReadLine();

আমার সিস্টেমে; অ্যারে ধরে পুনরাবৃত্তি করতে 33 মিলিয়ন লাগল; তালিকাটি পুনরাবৃত্তি করে 66 মি সেকেন্ড লাগল।

সত্যি কথা বলতে, আমি আশা করিনি যে তারতম্যটি এতটা হবে। সুতরাং, আমি আমার পুনরাবৃত্তি একটি লুপে রেখেছি: এখন, আমি উভয় পুনরাবৃত্তিটি 1000 বার সম্পাদন করি। ফলাফলগুলি হ'ল:

তালিকাটি পুনরাবৃত্তি করতে 67146 ম্যাসেক লাগল অ্যারেটি পুনরাবৃত্তি করে 40821 ম্যাসি

এখন, প্রকরণটি এত বড় নয়, তবে এখনও ...

অতএব, আমি শুরু করেছি। নেট প্রতিফলক, এবং তালিকা শ্রেণীর সূচকের প্রাপ্ত, এটি দেখতে:

public T get_Item(int index)
{
    if (index >= this._size)
    {
        ThrowHelper.ThrowArgumentOutOfRangeException();
    }
    return this._items[index];
}

আপনি দেখতে পাচ্ছেন, আপনি যখন তালিকার সূচকটি ব্যবহার করেন, তালিকাটি আপনি অভ্যন্তরীণ অ্যারের সীমানার বাইরে চলে যাচ্ছেন না কিনা তা পরীক্ষা করে। এই অতিরিক্ত চেক একটি ব্যয় সঙ্গে আসে।


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

1
এটি ফেরত দেবে না _ ইতিমধ্যে একটি ব্যতিক্রম ছুঁড়ে যদি সূচক সীমার বাইরে ছিল? শেষ ফলাফলটি এটির সাথে বা ব্যতীত যখন হয় তখন নেট কেন এই অতিরিক্ত চেক করে?
জন মার্সিয়ার 12

@ জন মার্সিয়ার এই চেকটি তালিকার আকারের (বর্তমানে থাকা আইটেমের সংখ্যা) এর বিপরীতে, যা _items অ্যারের ক্ষমতার চেয়ে পৃথক এবং সম্ভবত কম। প্রতিটি সংযোজনের জন্য পুনরায় বরাদ্দ প্রয়োজন না করে ভবিষ্যতের আইটেমগুলিকে দ্রুত তৈরি করার জন্য অ্যারের অতিরিক্ত ক্ষমতা সহ বরাদ্দ করা হয়।
ট্রসভি

21

যদি আপনি কেবলমাত্র একটি লুপের বাইরে (কোনও লুপে নয়) পাচ্ছেন তবে উভয়ই চেক করে বেঁধে রাখে (আপনি পরিচালিত কোড মনে রাখবেন) এটি কেবলমাত্র তালিকাটি দু'বার করে। এটি সম্ভবত কোনও বড় বিষয় নয় কেন তার জন্য নোটগুলি পরে দেখুন।

আপনি যদি নিজের জন্য ব্যবহার করেন (int int i = 0; i <x। [দৈর্ঘ্য / গণনা]; i++) তবে মূল পার্থক্যটি নীচে রয়েছে:

  • এরে:
    • সীমা চেক অপসারণ করা হয়
  • তালিকাসমূহ
    • সীমা পরীক্ষা করা হয়

আপনি যদি ফোরচ ব্যবহার করছেন তবে মূল পার্থক্যটি নিম্নরূপ:

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

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


11

[ আরও দেখুন এই প্রশ্নের ]

আমি সত্যিকারের এলোমেলো নম্বরগুলি ব্যবহার করার জন্য মার্কের উত্তরটি পরিবর্তন করেছি এবং সব ক্ষেত্রে একই কাজ করব।

ফলাফল:

         ভবিষ্যদ্বাণী জন্য
অ্যারে: 1575ms 1575 মিমি (+ 0%)
তালিকা: 1630ms 2627 মিমি (+ 61%)
         (+ 3%) (+ 67%)

(চেকসাম: -1000038876)

ভিএস ২০০৮ এসপি 1 এর অধীনে প্রকাশ হিসাবে সংকলিত। Q6600@2.40GHz, .NET 3.5 এসপি 1 এ ডিবাগিং ছাড়াই চলছে।

কোড:

class Program
{
    static void Main(string[] args)
    {
        List<int> list = new List<int>(6000000);
        Random rand = new Random(1);
        for (int i = 0; i < 6000000; i++)
        {
            list.Add(rand.Next());
        }
        int[] arr = list.ToArray();

        int chk = 0;
        Stopwatch watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 100; rpt++)
        {
            int len = list.Count;
            for (int i = 0; i < len; i++)
            {
                chk += list[i];
            }
        }
        watch.Stop();
        Console.WriteLine("List/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk);

        chk = 0;
        watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 100; rpt++)
        {
            int len = arr.Length;
            for (int i = 0; i < len; i++)
            {
                chk += arr[i];
            }
        }
        watch.Stop();
        Console.WriteLine("Array/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk);

        chk = 0;
        watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 100; rpt++)
        {
            foreach (int i in list)
            {
                chk += i;
            }
        }
        watch.Stop();
        Console.WriteLine("List/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk);

        chk = 0;
        watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 100; rpt++)
        {
            foreach (int i in arr)
            {
                chk += i;
            }
        }
        watch.Stop();
        Console.WriteLine("Array/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk);
        Console.WriteLine();

        Console.ReadLine();
    }
}

এটি অদ্ভুত - আমি স্রেফ আপনার সঠিক কোডটি চালিয়েছি, কমান্ড লাইন (3.5sp1) থেকে / ও + / ডিবাগ- দিয়ে তৈরি এবং আমার ফলাফলগুলি: তালিকা / জন্য: 1524; অ্যারে / ফর: 1472; তালিকা / foreach: 4128; অ্যারে / foreach: 1484।
জন স্কিটি

আপনি বলছেন এটি মুক্তি হিসাবে সংকলিত হয়েছিল - আমি কি এটি ঠিক করতে পারি যে এটি ডিবাগ করার চেয়ে আপনি এটি চালিয়েছেন? নির্বোধ প্রশ্ন, আমি জানি, তবে আমি ফলাফলটি অন্যথায় ব্যাখ্যা করতে পারি না ...
জন স্কিটি

2

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


2

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


2

এখানে একটি অভিধান যা ডিকোরিয়ান্স ব্যবহার করে, গণ্য:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

static class Program
{
    static void Main()
    {
        List<int> list = new List<int>(6000000);

        for (int i = 0; i < 6000000; i++)
        {
                list.Add(i);
        }
        Console.WriteLine("Count: {0}", list.Count);

        int[] arr = list.ToArray();
        IEnumerable<int> Ienumerable = list.ToArray();
        Dictionary<int, bool> dict = list.ToDictionary(x => x, y => true);

        int chk = 0;
        Stopwatch watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 100; rpt++)
        {
            int len = list.Count;
            for (int i = 0; i < len; i++)
            {
                chk += list[i];
            }
        }
        watch.Stop();
        Console.WriteLine("List/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk);

        chk = 0;
        watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 100; rpt++)
        {
            for (int i = 0; i < arr.Length; i++)
            {
                chk += arr[i];
            }
        }
        watch.Stop();
        Console.WriteLine("Array/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk);

        chk = 0;
        watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 100; rpt++)
        {
            foreach (int i in Ienumerable)
            {
                chk += i;
            }
        }

        Console.WriteLine("Ienumerable/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk);

        chk = 0;
        watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 100; rpt++)
        {
            foreach (int i in dict.Keys)
            {
                chk += i;
            }
        }

        Console.WriteLine("Dict/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk);


        chk = 0;
        watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 100; rpt++)
        {
            foreach (int i in list)
            {
                chk += i;
            }
        }

        watch.Stop();
        Console.WriteLine("List/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk);

        chk = 0;
        watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 100; rpt++)
        {
            foreach (int i in arr)
            {
                chk += i;
            }
        }
        watch.Stop();
        Console.WriteLine("Array/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk);



        chk = 0;
        watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 100; rpt++)
        {
            foreach (int i in Ienumerable)
            {
                chk += i;
            }
        }
        watch.Stop();
        Console.WriteLine("Ienumerable/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk);

        chk = 0;
        watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 100; rpt++)
        {
            foreach (int i in dict.Keys)
            {
                chk += i;
            }
        }
        watch.Stop();
        Console.WriteLine("Dict/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk);

        Console.ReadLine();
    }
}

2

উপাদান সংখ্যা বৃদ্ধি করে ক্ষমতা যুক্ত করার চেষ্টা করবেন না।

কর্মক্ষমতা

List For Add: 1ms
Array For Add: 2397ms

    Stopwatch watch;
        #region --> List For Add <--

        List<int> intList = new List<int>();
        watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 60000; rpt++)
        {
            intList.Add(rand.Next());
        }
        watch.Stop();
        Console.WriteLine("List For Add: {0}ms", watch.ElapsedMilliseconds);
        #endregion

        #region --> Array For Add <--

        int[] intArray = new int[0];
        watch = Stopwatch.StartNew();
        int sira = 0;
        for (int rpt = 0; rpt < 60000; rpt++)
        {
            sira += 1;
            Array.Resize(ref intArray, intArray.Length + 1);
            intArray[rpt] = rand.Next();

        }
        watch.Stop();
        Console.WriteLine("Array For Add: {0}ms", watch.ElapsedMilliseconds);

        #endregion

আমি একটি অ্যারের times০k বারের আকারটি ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে চলতে চলেছি ... বাস্তব বিশ্বে ব্যবহারের ক্ষেত্রে অবশ্যই আপনার প্রয়োজন কত অতিরিক্ত স্লট প্রয়োজন তা পরীক্ষা করতে হবে, এটির দৈর্ঘ্য + 60 ক আকারে পরিবর্তন করুন এবং তারপরে সন্নিবেশগুলি দিয়ে জিপ করুন।
tobriand

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

2

আমি উদ্বিগ্ন ছিলাম যে অন্য জবাবগুলিতে পোস্ট করা বেঞ্চমার্কগুলি এখনও কম্পাইলারকে লুপগুলি অনুকূল করতে, নির্মূল করতে বা মার্জ করার জন্য জায়গা ছেড়ে যাবে তাই আমি একটি লিখেছিলাম:

  • অপ্রত্যাশিত ইনপুট ব্যবহৃত (এলোমেলো)
  • কনসোলে মুদ্রিত ফলাফল সহ একটি গণনা চালায়
  • প্রতিটি পুনরাবৃত্তি ইনপুট ডেটা পরিবর্তন করে

আইএললিস্টে আবৃত একটি অ্যারের অ্যাক্সেসের চেয়ে প্রত্যক্ষ অ্যারেতে প্রায় 250% ভাল পারফরম্যান্স রয়েছে ফলাফল:

  • 1 বিলিয়ন অ্যারে অ্যাক্সেসগুলি: 4000 এমএস
  • 1 বিলিয়ন তালিকা অ্যাক্সেস: 10000 এমএস
  • 100 মিলিয়ন অ্যারে অ্যাক্সেসগুলি: 350 এমএস
  • 100 মিলিয়ন তালিকার অ্যাক্সেসগুলি: 1000 এমএস

কোডটি এখানে:

static void Main(string[] args) {
  const int TestPointCount = 1000000;
  const int RepetitionCount = 1000;

  Stopwatch arrayTimer = new Stopwatch();
  Stopwatch listTimer = new Stopwatch();

  Point2[] points = new Point2[TestPointCount];
  var random = new Random();
  for (int index = 0; index < TestPointCount; ++index) {
    points[index].X = random.NextDouble();
    points[index].Y = random.NextDouble();
  }

  for (int repetition = 0; repetition <= RepetitionCount; ++repetition) {
    if (repetition > 0) { // first repetition is for cache warmup
      arrayTimer.Start();
    }
    doWorkOnArray(points);
    if (repetition > 0) { // first repetition is for cache warmup
      arrayTimer.Stop();
    }

    if (repetition > 0) { // first repetition is for cache warmup
      listTimer.Start();
    }
    doWorkOnList(points);
    if (repetition > 0) { // first repetition is for cache warmup
      listTimer.Stop();
    }
  }

  Console.WriteLine("Ignore this: " + points[0].X + points[0].Y);
  Console.WriteLine(
    string.Format(
      "{0} accesses on array took {1} ms",
      RepetitionCount * TestPointCount, arrayTimer.ElapsedMilliseconds
    )
  );
  Console.WriteLine(
    string.Format(
      "{0} accesses on list took {1} ms",
      RepetitionCount * TestPointCount, listTimer.ElapsedMilliseconds
    )
  );

}

private static void doWorkOnArray(Point2[] points) {
  var random = new Random();

  int pointCount = points.Length;

  Point2 accumulated = Point2.Zero;
  for (int index = 0; index < pointCount; ++index) {
    accumulated.X += points[index].X;
    accumulated.Y += points[index].Y;
  }

  accumulated /= pointCount;

  // make use of the result somewhere so the optimizer can't eliminate the loop
  // also modify the input collection so the optimizer can merge the repetition loop
  points[random.Next(0, pointCount)] = accumulated;
}

private static void doWorkOnList(IList<Point2> points) {
  var random = new Random();

  int pointCount = points.Count;

  Point2 accumulated = Point2.Zero;
  for (int index = 0; index < pointCount; ++index) {
    accumulated.X += points[index].X;
    accumulated.Y += points[index].Y;
  }

  accumulated /= pointCount;

  // make use of the result somewhere so the optimizer can't eliminate the loop
  // also modify the input collection so the optimizer can merge the repetition loop
  points[random.Next(0, pointCount)] = accumulated;
}

0

যেহেতু তালিকা <> অভ্যন্তরীণভাবে অ্যারে ব্যবহার করে, তাই প্রাথমিক কার্যকারিতা একই হওয়া উচিত। দুটি কারণ, কেন তালিকাটি কিছুটা ধীর হতে পারে:

  • তালিকার কোনও উপাদান সন্ধান করতে তালিকার একটি পদ্ধতি বলা হয়, যা অন্তর্নিহিত অ্যারেতে চেহারা করে। সুতরাং আপনার এখানে একটি অতিরিক্ত পদ্ধতি কল প্রয়োজন। অন্যদিকে সংকলক সম্ভবত এটি সনাক্ত করতে পারে এবং "অপ্রয়োজনীয়" কলকে অপ্টিমাইজ করে।
  • সংকলক কিছু বিশেষ অপ্টিমাইজেশন করতে পারে যদি এটি অ্যারের আকার জানে, এটি অজানা দৈর্ঘ্যের তালিকার জন্য করতে পারে না। আপনার তালিকায় কেবলমাত্র কয়েকটি উপাদান থাকলে এটি কিছু কার্যকারিতা উন্নতি করতে পারে bring

এটি আপনার জন্য কোনও পার্থক্য করে কিনা তা খতিয়ে দেখার জন্য, আপনি যে আকারটি ব্যবহার করার পরিকল্পনা করছেন তার তালিকার সাথে পোস্টের সময়কৃত কার্যকারিতাটি সর্বোত্তমভাবে সামঞ্জস্য করুন এবং দেখুন যে আপনার বিশেষ মামলার ফলাফলগুলি কীভাবে রয়েছে।


0

যেহেতু আমার অনুরূপ প্রশ্ন ছিল এটি আমাকে দ্রুত শুরু করেছে।

আমার প্রশ্নটি কিছুটা সুনির্দিষ্ট, 'একটি রিফ্লেক্সিভ অ্যারে বাস্তবায়নের জন্য দ্রুততম পদ্ধতি কী'

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

সজ্জা, আমি একটি ধ্রুবক ব্যবহার করে একটি পরীক্ষা করি, যা আমাকে লুপ সহ একটি নির্দিষ্ট সময় দেয়। প্রকৃত অ্যাক্সেস বাদ দিয়ে এটি একটি 'বেয়ার' সময়। তারপরে আমি বিষয় কাঠামো অ্যাক্সেস সহ একটি পরীক্ষা করি, এটি আমাকে এবং 'ওভারহেড অন্তর্ভুক্ত' সময়, লুপিং এবং প্রকৃত অ্যাক্সেস দেয়।

'বেয়ার' টাইমিং এবং 'ওভারহেড অন্তর্ভুক্ত' টাইমিংয়ের মধ্যে পার্থক্য আমাকে 'স্ট্রাকচার অ্যাক্সেস' টাইমিংয়ের ইঙ্গিত দেয়।

তবে এই সময়টি কতটা সঠিক? পরীক্ষার সময় উইন্ডোজ শুরের জন্য কিছু সময় স্লাইসিং করবে। সময় কাটানোর সময় সম্পর্কে আমার কাছে কোনও তথ্য নেই তবে আমি ধারনা করি এটি পরীক্ষার সময় এবং দশ মেকের ক্রম হিসাবে সমানভাবে বিতরণ করা হয় যার অর্থ সময়সীমার যথাযথতা +/- 100 ম্যাসেক বা এর মতো হওয়া উচিত। কিছুটা মোটামুটি অনুমান? যাইহোক পদ্ধতিগত mearure ত্রুটির একটি উত্স।

এছাড়াও, পরীক্ষাগুলি কোনও অনুকূলকরণ ছাড়াই 'ডিবাগ' মোডে করা হয়েছিল। অন্যথায় সংকলক প্রকৃত পরীক্ষার কোডটি পরিবর্তন করতে পারে।

সুতরাং, আমি দুটি ফলাফল পেয়েছি, একটি ধ্রুবক হিসাবে চিহ্নিত, '(সি)', এবং একটি 'অ্যাক্সেসের জন্য চিহ্নিত' (এন) 'এবং পার্থক্য' ডিটি 'আমাকে জানায় যে প্রকৃত অ্যাক্সেসটি কত সময় নেয়।

এবং এটি ফলাফল:

          Dictionary(c)/for: 1205ms (600000000)
          Dictionary(n)/for: 8046ms (589725196)
 dt = 6841

                List(c)/for: 1186ms (1189725196)
                List(n)/for: 2475ms (1779450392)
 dt = 1289

               Array(c)/for: 1019ms (600000000)
               Array(n)/for: 1266ms (589725196)
 dt = 247

 Dictionary[key](c)/foreach: 2738ms (600000000)
 Dictionary[key](n)/foreach: 10017ms (589725196)
 dt = 7279

            List(c)/foreach: 2480ms (600000000)
            List(n)/foreach: 2658ms (589725196)
 dt = 178

           Array(c)/foreach: 1300ms (600000000)
           Array(n)/foreach: 1592ms (589725196)
 dt = 292


 dt +/-.1 sec   for    foreach
 Dictionary     6.8       7.3
 List           1.3       0.2
 Array          0.2       0.3

 Same test, different system:
 dt +/- .1 sec  for    foreach
 Dictionary     14.4   12.0
       List      1.7    0.1
      Array      0.5    0.7

সময়ের ত্রুটি সম্পর্কে আরও ভাল অনুমানের সাথে (সময় কাটানোর কারণে পদ্ধতিগত পরিমাপ ত্রুটিটি কীভাবে সরিয়ে নেওয়া যায়?) ফলাফল সম্পর্কে আরও বলা যেতে পারে।

দেখে মনে হচ্ছে লিস্ট / ফোরচের দ্রুত অ্যাক্সেস রয়েছে তবে ওভারহেড এটি হত্যা করছে।

তালিকা / ফর এবং তালিকা / পূর্বাভাসের মধ্যে পার্থক্য হ'ল স্তম্ভ। কিছু নগদ অর্থ জড়িত হতে পারে?

আরও একটি অ্যারে অ্যাক্সেসের জন্য আপনি forলুপ বা লুপ ব্যবহার করেন তা foreachবিবেচ্য নয়। সময়সীমার ফলাফল এবং এর যথার্থতা ফলাফলগুলিকে 'তুলনীয়' করে তোলে।

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

পরিবর্তিত পরীক্ষার কোডটি এখানে।

Dictionary<int, int> dict = new Dictionary<int, int>(6000000);
List<int> list = new List<int>(6000000);
Random rand = new Random(12345);
for (int i = 0; i < 6000000; i++)
{
    int n = rand.Next(5000);
    dict.Add(i, n);
    list.Add(n);
}
int[] arr = list.ToArray();

int chk = 0;
Stopwatch watch = Stopwatch.StartNew();
for (int rpt = 0; rpt < 100; rpt++)
{
    int len = dict.Count;
    for (int i = 0; i < len; i++)
    {
        chk += 1; // dict[i];
    }
}
watch.Stop();
long c_dt = watch.ElapsedMilliseconds;
Console.WriteLine("         Dictionary(c)/for: {0}ms ({1})", c_dt, chk);

chk = 0;
watch = Stopwatch.StartNew();
for (int rpt = 0; rpt < 100; rpt++)
{
    int len = dict.Count;
    for (int i = 0; i < len; i++)
    {
        chk += dict[i];
    }
}
watch.Stop();
long n_dt = watch.ElapsedMilliseconds;
Console.WriteLine("         Dictionary(n)/for: {0}ms ({1})", n_dt, chk);
Console.WriteLine("dt = {0}", n_dt - c_dt);

watch = Stopwatch.StartNew();
for (int rpt = 0; rpt < 100; rpt++)
{
    int len = list.Count;
    for (int i = 0; i < len; i++)
    {
        chk += 1; // list[i];
    }
}
watch.Stop();
c_dt = watch.ElapsedMilliseconds;
Console.WriteLine("               List(c)/for: {0}ms ({1})", c_dt, chk);

watch = Stopwatch.StartNew();
for (int rpt = 0; rpt < 100; rpt++)
{
    int len = list.Count;
    for (int i = 0; i < len; i++)
    {
        chk += list[i];
    }
}
watch.Stop();
n_dt = watch.ElapsedMilliseconds;
Console.WriteLine("               List(n)/for: {0}ms ({1})", n_dt, chk);
Console.WriteLine("dt = {0}", n_dt - c_dt);

chk = 0;
watch = Stopwatch.StartNew();
for (int rpt = 0; rpt < 100; rpt++)
{
    for (int i = 0; i < arr.Length; i++)
    {
        chk += 1; // arr[i];
    }
}
watch.Stop();
c_dt = watch.ElapsedMilliseconds;
Console.WriteLine("              Array(c)/for: {0}ms ({1})", c_dt, chk);

chk = 0;
watch = Stopwatch.StartNew();
for (int rpt = 0; rpt < 100; rpt++)
{
    for (int i = 0; i < arr.Length; i++)
    {
        chk += arr[i];
    }
}
watch.Stop();
n_dt = watch.ElapsedMilliseconds;
Console.WriteLine("Array(n)/for: {0}ms ({1})", n_dt, chk);
Console.WriteLine("dt = {0}", n_dt - c_dt);

chk = 0;
watch = Stopwatch.StartNew();
for (int rpt = 0; rpt < 100; rpt++)
{
    foreach (int i in dict.Keys)
    {
        chk += 1; // dict[i]; ;
    }
}
watch.Stop();
c_dt = watch.ElapsedMilliseconds;
Console.WriteLine("Dictionary[key](c)/foreach: {0}ms ({1})", c_dt, chk);

chk = 0;
watch = Stopwatch.StartNew();
for (int rpt = 0; rpt < 100; rpt++)
{
    foreach (int i in dict.Keys)
    {
        chk += dict[i]; ;
    }
}
watch.Stop();
n_dt = watch.ElapsedMilliseconds;
Console.WriteLine("Dictionary[key](n)/foreach: {0}ms ({1})", n_dt, chk);
Console.WriteLine("dt = {0}", n_dt - c_dt);

chk = 0;
watch = Stopwatch.StartNew();
for (int rpt = 0; rpt < 100; rpt++)
{
    foreach (int i in list)
    {
        chk += 1; // i;
    }
}
watch.Stop();
c_dt = watch.ElapsedMilliseconds;
Console.WriteLine("           List(c)/foreach: {0}ms ({1})", c_dt, chk);

chk = 0;
watch = Stopwatch.StartNew();
for (int rpt = 0; rpt < 100; rpt++)
{
    foreach (int i in list)
    {
        chk += i;
    }
}
watch.Stop();
n_dt = watch.ElapsedMilliseconds;
Console.WriteLine("           List(n)/foreach: {0}ms ({1})", n_dt, chk);
Console.WriteLine("dt = {0}", n_dt - c_dt);

chk = 0;
watch = Stopwatch.StartNew();
for (int rpt = 0; rpt < 100; rpt++)
{
    foreach (int i in arr)
    {
        chk += 1; // i;
    }
}
watch.Stop();
c_dt = watch.ElapsedMilliseconds;
Console.WriteLine("          Array(c)/foreach: {0}ms ({1})", c_dt, chk);

chk = 0;
watch = Stopwatch.StartNew();
for (int rpt = 0; rpt < 100; rpt++)
{
    foreach (int i in arr)
    {
        chk += i;
    }
}
watch.Stop();
n_dt = watch.ElapsedMilliseconds;
Console.WriteLine("Array(n)/foreach: {0}ms ({1})", n_dt, chk);
Console.WriteLine("dt = {0}", n_dt - c_dt);

0

কিছু সংক্ষিপ্ত পরীক্ষায় আমি দু'জনের সংমিশ্রণটি পেয়েছি যা আমি যুক্তিযুক্ত ঘন ম্যাথ বলব তার চেয়ে ভাল হতে:

টাইপ করুন: List<double[]>

সময়: 00: 00: 05.1861300

টাইপ করুন: List<List<double>>

সময়: 00: 00: 05.7941351

টাইপ করুন: double[rows * columns]

সময়: 00: 00: 06.0547118

কোড চালানো:

int rows = 10000;
int columns = 10000;

IMatrix Matrix = new IMatrix(rows, columns);

Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();


for (int r = 0; r < Matrix.Rows; r++)
    for (int c = 0; c < Matrix.Columns; c++)
        Matrix[r, c] = Math.E;

for (int r = 0; r < Matrix.Rows; r++)
    for (int c = 0; c < Matrix.Columns; c++)
        Matrix[r, c] *= -Math.Log(Math.E);


stopwatch.Stop();
TimeSpan ts = stopwatch.Elapsed;

Console.WriteLine(ts.ToString());

আমি আশা করি আমাদের .NET টিম System.Numerics.Vectorsক্লাসটি দিয়ে কিছু উচ্চতর হার্ডওয়ার এক্সিলেনটেড ম্যাট্রিক্স ক্লাস করুক !

এই অঞ্চলে আরও কিছু কাজ করে সি # সেরা এমএল ভাষা হতে পারে!

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