কেন কোথায় এবং সিলেক্ট আউটফর্মফর্মিং সিলেক্ট করুন?


145

আমার একটি ক্লাস আছে, এটির মতো:

public class MyClass
{
    public int Value { get; set; }
    public bool IsValid { get; set; }
}

প্রকৃতপক্ষে এটি অনেক বড়, তবে এটি সমস্যাটি (অদ্ভুততা) পুনরায় তৈরি করে।

আমি যোগফল পেতে চাই Value , যেখানে উদাহরণটি বৈধ। এখনও অবধি আমি এর দুটি সমাধান খুঁজে পেয়েছি।

প্রথমটি হ'ল:

int result = myCollection.Where(mc => mc.IsValid).Select(mc => mc.Value).Sum();

দ্বিতীয়টি হ'ল এটি:

int result = myCollection.Select(mc => mc.IsValid ? mc.Value : 0).Sum();

আমি সবচেয়ে দক্ষ পদ্ধতি পেতে চাই। আমি প্রথমে ভেবেছিলাম যে দ্বিতীয়টি আরও দক্ষ হবে। তারপরে আমার তাত্ত্বিক অংশটি "ভাল, একটি হ'ল ও (এন + এম + এম), অন্যটি হ'ল (এন + এন) going কম সাথে "। আমি ভেবেছিলাম তারা সমান পারফর্ম করবে। সম্পাদনা: এবং তারপরে @ মার্টিন নির্দেশ করেছেন যে কোথায় এবং নির্বাচনগুলি একত্রিত হয়েছে, সুতরাং এটি আসলে ও (এম + এন) হওয়া উচিত। তবে নীচের দিকে নজর দিলে মনে হয় এটি সম্পর্কিত নয়।


তাই আমি পরীক্ষায় ফেলেছি।

(এটি 100+ লাইনস, তাই আমি ভেবেছিলাম এটিকে একটি সংক্ষেপ হিসাবে পোস্ট করা ভাল)
ফলাফলগুলি ছিল আকর্ষণীয়।

0% টাই সহনশীলতা সহ:

আঁশগুলি প্রায় ~ 30 পয়েন্টের পক্ষে Selectএবং পক্ষে Where

How much do you want to be the disambiguation percentage?
0
Starting benchmarking.
Ties: 0
Where + Select: 65
Select: 36

2% টাই সহনশীলতা সহ:

এটি একই, কিছু বাদে তারা 2% এর মধ্যে ছিল। আমি বলব যে এটি একটি ন্যূনতম মার্জিন এরর। Selectএবং Whereএখন মাত্র একটি ~ 20 পয়েন্ট সীসা আছে।

How much do you want to be the disambiguation percentage?
2
Starting benchmarking.
Ties: 6
Where + Select: 58
Select: 37

5% টাই সহনশীলতা সহ:

এটিই আমি আমার সর্বাধিক ব্যবস্থার ত্রুটি হিসাবে বলতে চাই। এটি এটি এর জন্য কিছুটা ভাল করে তোলে Selectতবে খুব বেশি নয়।

How much do you want to be the disambiguation percentage?
5
Starting benchmarking.
Ties: 17
Where + Select: 53
Select: 31

10% টাই সহনশীলতা সহ:

এটি আমার ত্রুটির প্রান্তের বাইরে, তবে আমি এখনও ফলাফলটিতে আগ্রহী। কারণ এটি এখন Selectএবং Whereবিশ পয়েন্টের নেতৃত্ব দেয় যা কিছু সময়ের জন্য ছিল।

How much do you want to be the disambiguation percentage?
10
Starting benchmarking.
Ties: 36
Where + Select: 44
Select: 21

25% টাই সহনশীলতা সহ:

এই ভাবে, হয় উপায় ত্রুটির আমার মার্জিন বাইরে, কিন্তু আমি এখনও ফলাফলে আগ্রহী কারণ Selectএবং Where এখনও (প্রায়) তাদের 20 পয়েন্টে এগিয়ে রাখা। দেখে মনে হচ্ছে এটি একটি স্বতন্ত্র কয়েকটিতে এটি আউটক্লাসিং করছে, এবং এটিই এটির নেতৃত্ব দেয়।

How much do you want to be the disambiguation percentage?
25
Starting benchmarking.
Ties: 85
Where + Select: 16
Select: 0


এখন, আমি অনুমান করছি যে 20 পয়েন্টে এগিয়ে মধ্যম, যেখানে তারা উভয় পেতে আবদ্ধ হন থেকে এসেছেন প্রায় একই কর্মক্ষমতা। আমি এটি চেষ্টা করতে এবং এটি লগ করতে পারে, তবে এটি নেওয়া সম্পূর্ণ তথ্য হবে load একটি গ্রাফ আরও ভাল হবে, আমার ধারণা।

তাই আমি কি করেছি।

বনাম নির্বাচন করুন এবং কোথায় নির্বাচন করুন।

এটি দেখায় যে Selectলাইনটি স্থির (প্রত্যাশিত) রাখে এবং Select + Whereলাইনটি উপরে উঠে যায় (প্রত্যাশিত)। যাইহোক, আমার ধাঁধাটি কেন এটি Select50 বা তার আগেরটির সাথে পূরণ হয় না : আসলে আমি 50 এরও আগে প্রত্যাশা করছিলাম, কারণ অতিরিক্ত গুনী তৈরি করতে হয়েছিলSelect এবং Where। মানে, এটি 20-পয়েন্টের সীসা দেখায়, তবে এটি কেন তা ব্যাখ্যা করে না। এটি, আমার ধারণা, এটিই আমার প্রশ্নের মূল বিষয়।

কেন এটি এমন আচরণ করে? আমার কি এটি বিশ্বাস করা উচিত? যদি না হয়, আমি অন্য একটি বা এই ব্যবহার করা উচিত?


@ কিংকং যেমন মন্তব্যে উল্লিখিত হয়েছে, আপনি তাও ব্যবহার করতে পারেন Sum । সুতরাং আমার দুটি বিকল্প এখন এটিতে পরিবর্তন করা হয়েছে:

প্রথম:

int result = myCollection.Where(mc => mc.IsValid).Sum(mc => mc.Value);

দ্বিতীয়ত:

int result = myCollection.Sum(mc => mc.IsValid ? mc.Value : 0);

আমি এটিকে কিছুটা খাটো করে তুলব, কিন্তু:

How much do you want to be the disambiguation percentage?
0
Starting benchmarking.
Ties: 0
Where: 60
Sum: 41
How much do you want to be the disambiguation percentage?
2
Starting benchmarking.
Ties: 8
Where: 55
Sum: 38
How much do you want to be the disambiguation percentage?
5
Starting benchmarking.
Ties: 21
Where: 49
Sum: 31
How much do you want to be the disambiguation percentage?
10
Starting benchmarking.
Ties: 39
Where: 41
Sum: 21
How much do you want to be the disambiguation percentage?
25
Starting benchmarking.
Ties: 85
Where: 16
Sum: 0

বিশ-পয়েন্টের সীসা এখনও রয়েছে, অর্থাত এটি মন্তব্যে @ মার্সিনের দ্বারা নির্দেশিত Whereএবং Selectসংমিশ্রণের সাথে কিছু করার নেই ।

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


1
আমি বলব যে এটি কত ব্যয়বহুল এবং অ্যাক্সেসের উপর নির্ভর করে mc.Value
মেডিনোক

14
@ It'sNotALie। Where+ Selectইনপুট সংগ্রহের ক্ষেত্রে দুটি পৃথক পুনরাবৃত্তি ঘটায় না। অবজেক্টগুলিকে লিনকিউ এটিকে একটি পুনরাবৃত্তিতে অনুকূলিত করে। আমার ব্লগ পোস্টে
মার্সিনজুরাসেক

4
মজাদার. আমাকে কেবল উল্লেখ করতে দিন যে একটি অ্যারের উপরে লুপের জন্য সেরা লিনকিউ সমাধানের চেয়ে 10x দ্রুত হবে। সুতরাং আপনি যদি পারফের জন্য শিকার করতে যান তবে প্রথমে লিনকিউ ব্যবহার করবেন না।
usr

2
কখনও কখনও লোকেরা প্রকৃত গবেষণার পরে জিজ্ঞাসা করে, এটি একটি উদাহরণ প্রশ্ন: আমি সি # নই ব্যবহারকারী হট-প্রশ্ন-তালিকা থেকে এসেছেন।
গ্রিজেশ চৌহান

2
@ উইসাগন এটি একটি ভাল বিষয়। যাইহোক, যদি এটি শাখা বনাম শর্তাধীন পদক্ষেপের কারণে হয়, তবে আমরা সর্বাধিক নাটকীয় পার্থক্য 50% / 50% দেখতে আশা করব। এখানে, আমরা প্রান্তগুলিতে সর্বাধিক নাটকীয় পার্থক্য দেখতে পাই, যেখানে শাখা প্রশাখা সবচেয়ে অনুমানযোগ্য। যদি কোথায় শাখা থাকে এবং ত্রৈমাসিক শর্তযুক্ত পদক্ষেপ হয়, তবে আমরা আশা করব যে সমস্ত উপাদান বৈধ হলে এই সময়গুলি আবার ফিরে আসবে, তবে এটি কখনই ফিরে আসবে না।
জন সেং

উত্তর:


131

Selectপুরো সেটটি একবারে পুনরাবৃত্তি করে এবং প্রতিটি আইটেমের জন্য শর্তসাপেক্ষ শাখা (বৈধতার জন্য পরীক্ষা করা) এবং একটি +ক্রিয়াকলাপ সম্পাদন করে।

Where+Selectএকটি পুনরাবৃত্তি তৈরি করে যা বৈধ আইটেমগুলিতে কেবল yieldএকটি সম্পাদন করে অবৈধ উপাদানগুলি ( তাদের নয় ) এড়িয়ে যায় +

সুতরাং, এর জন্য ব্যয়টি Selectহ'ল:

t(s) = n * ( cost(check valid) + cost(+) )

এবং এর জন্য Where+Select:

t(ws) = n * ( cost(check valid) + p(valid) * (cost(yield) + cost(+)) )

কোথায়:

  • p(valid) তালিকার কোনও আইটেম বৈধ হওয়ার সম্ভাবনা।
  • cost(check valid) যা শাখার মূল্য যাচাইয়ের জন্য যাচাই করে
  • cost(yield)whereএটির পুনরুক্তির নতুন রাজ্য নির্মাণের ব্যয় যা Selectসংস্করণটি ব্যবহার করে এমন সরল পুনরুক্তির চেয়ে জটিল ।

যেহেতু আপনি দেখতে পারেন, একটি দেওয়া n, Selectসংস্করণ একটি ধ্রুবক, হয় যেহেতু Where+Selectসংস্করণের সাথে একটি রৈখিক সমীকরণ হয় p(valid)একটি পরিবর্তনশীল হিসাবে। খরচের আসল মানগুলি দুটি লাইনের ছেদ বিন্দু নির্ধারণ করে এবং যেহেতু এর cost(yield)চেয়ে আলাদা হতে পারে cost(+), তারা অগত্যা p(valid)= 0.5 তে ছেদ করে না ।


34
একমাত্র উত্তর হওয়ার জন্য +1 (এখনও অবধি) যা আসলে প্রশ্নের সমাধান করে, উত্তরটি অনুমান করে না এবং কেবল "আমাকেও!" উত্পন্ন করে না! পরিসংখ্যান।
বাইনারি ওয়ারিয়ার

4
প্রযুক্তিগতভাবে লিনকিউ পদ্ধতিগুলি এমন অভিব্যক্তি গাছ তৈরি করে যা পুরো সংগ্রহের উপরে একবার "সেট" না করে চলে run
স্পোকাইক

কি cost(append)? যদিও সত্যিই ভাল উত্তর, এটি কেবলমাত্র পরিসংখ্যানের চেয়ে আলাদা কোণ থেকে দেখে।
ইটনাটালি

5
Whereকিছুই তৈরি করে না, কেবলমাত্র sourceঅনুক্রমটি পূরণ করে যদি সিকোয়েন্স থেকে সেই সময়ে একটি উপাদান ফেরত দেয়।
মার্সিনজুরাজেক

13
@ স্পাইকে - এক্সপ্রেশন গাছগুলি এখানে প্রাসঙ্গিক নয়, কারণ এটি লিনিক-টু-অবজেক্টস , লিনাক-টু-অ্যাক্ট-কিছু নয় (সত্তা, উদাহরণস্বরূপ)। যে পার্থক্য IEnumerable.Select(IEnumerable, Func)এবং IQueryable.Select(IQueryable, Expression<Func>)। আপনি ঠিক বলেছেন যে সংগ্রহের উপরে পুনরাবৃত্তি না হওয়া অবধি লিনকিউ "কিছুই না" করে যা সম্ভবত আপনি বোঝাতে চেয়েছিলেন।
কোবি

33

সময়-পার্থক্যের কারণ কী তা নিয়ে একটি গভীরতর ব্যাখ্যা এখানে।


Sum()জন্য ফাংশন IEnumerable<int>ভালো দেখায়:

public static int Sum(this IEnumerable<int> source)
{
    int sum = 0;
    foreach(int item in source)
    {
        sum += item;
    }
    return sum;
}

সি # তে, foreachকেবলমাত্র একটি পুনরাবৃত্তির নেট এর সংস্করণ, (বিভ্রান্ত হওয়ার দরকার নেই ) জন্য সিনট্যাকটিক চিনি । সুতরাং উপরের কোডটি আসলে এটিতে অনুবাদ করা হয়েছে:IEnumerator<T> IEnumerable<T>

public static int Sum(this IEnumerable<int> source)
{
    int sum = 0;

    IEnumerator<int> iterator = source.GetEnumerator();
    while(iterator.MoveNext())
    {
        int item = iterator.Current;
        sum += item;
    }
    return sum;
}

মনে রাখবেন, আপনি যে দুটি লাইনের কোডের সাথে তুলনা করছেন তা নিম্নরূপ

int result1 = myCollection.Where(mc => mc.IsValid).Sum(mc => mc.Value);
int result2 = myCollection.Sum(mc => mc.IsValid ? mc.Value : 0);

এখন এখানে লাথি:

লিনকিউ স্থগিত কার্যকরকরণ ব্যবহার করে । সুতরাং, যখন এটি প্রদর্শিত হতে পারে যে result1সংগ্রহের উপরে দুবার পুনরাবৃত্তি হয়, এটি আসলে একবারেই এটির পুনরাবৃত্তি করে। Where()শর্ত আসলে সময় প্রয়োগ করা হয় Sum()থেকে কল এর ভিতরে MoveNext() (এই জাদু করা সম্ভব ধন্যবাদ yield return)

এর অর্থ এই যে লুপের result1অভ্যন্তরে কোডটি while,

{
    int item = iterator.Current;
    sum += item;
}

শুধুমাত্র প্রতিটি আইটেমের সাথে একবার কার্যকর করা হয় mc.IsValid == true। তুলনা করে , সংগ্রহের প্রতিটি আইটেমের result2জন্য সেই কোডটি কার্যকর করা হবে । যে কারণে সাধারণত দ্রুত হয়।result1

(যদিও, দয়া করে মনে রাখবেন কলিং Where()শর্ত মধ্যে MoveNext(), এখনও কিছু ছোট ওভারহেড হয়েছে তাই সবচেয়ে যদি / আইটেম সব আছে mc.IsValid == true, result2আসলে দ্রুততর হবে!)


আশা করি এখন এটি পরিষ্কার হয়ে গেছে কেন result2সাধারণত ধীর হয়। এখন আমি ব্যাখ্যা করতে চাই কেন আমি মন্তব্যগুলিতে বলেছিলাম যে এই লিনকিউ পারফরম্যান্সের তুলনা কোনও বিষয় নয়

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

সুতরাং, আপনার লিনকিউ ওয়ার্কফ্লোটি দেখতে এমন হওয়া উচিত:

  1. সর্বত্র LINQ ব্যবহার করুন।
  2. প্রোফাইলের।
  3. প্রোফাইলার যদি বলে যে লিনকুই একটি বাধা কারণ, লিনকু ছাড়াই কোডের এই অংশটি আবার লিখুন।

ভাগ্যক্রমে, লিনকুই বাধা বিরল। কড়া, বাধা বিরল। আমি গত কয়েক বছরে কয়েকশ লিনকিউ বিবৃতি লিখেছি এবং <1% প্রতিস্থাপন শেষ করেছি। আর অধিকাংশ কারণে ছিল LINQ2EF বরং LINQ দোষ থাকার চেয়ে, 'গুলি দরিদ্র এসকিউএল অপ্টিমাইজেশান।

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


3
ছোট সংযোজন: শীর্ষ উত্তর স্থির করা হয়েছে।
ইটনাটালি

16

মজার ব্যাপার. আপনি কীভাবে Sum(this IEnumerable<TSource> source, Func<TSource, int> selector)সংজ্ঞায়িত জানেন ? এটি Selectপদ্ধতি ব্যবহার করে !

public static int Sum<TSource>(this IEnumerable<TSource> source, Func<TSource, int> selector)
{
    return source.Select(selector).Sum();
}

সুতরাং আসলে, এটি সব প্রায় একই কাজ করা উচিত। আমি নিজে নিজেই দ্রুত গবেষণা করেছি এবং ফলাফলগুলি এখানে:

Where -- mod: 1 result: 0, time: 371 ms
WhereSelect -- mod: 1  result: 0, time: 356 ms
Select -- mod: 1  result 0, time: 366 ms
Sum -- mod: 1  result: 0, time: 363 ms
-------------
Where -- mod: 2 result: 4999999, time: 469 ms
WhereSelect -- mod: 2  result: 4999999, time: 429 ms
Select -- mod: 2  result 4999999, time: 362 ms
Sum -- mod: 2  result: 4999999, time: 358 ms
-------------
Where -- mod: 3 result: 9999999, time: 441 ms
WhereSelect -- mod: 3  result: 9999999, time: 452 ms
Select -- mod: 3  result 9999999, time: 371 ms
Sum -- mod: 3  result: 9999999, time: 380 ms
-------------
Where -- mod: 4 result: 7500000, time: 571 ms
WhereSelect -- mod: 4  result: 7500000, time: 501 ms
Select -- mod: 4  result 7500000, time: 406 ms
Sum -- mod: 4  result: 7500000, time: 397 ms
-------------
Where -- mod: 5 result: 7999999, time: 490 ms
WhereSelect -- mod: 5  result: 7999999, time: 477 ms
Select -- mod: 5  result 7999999, time: 397 ms
Sum -- mod: 5  result: 7999999, time: 394 ms
-------------
Where -- mod: 6 result: 9999999, time: 488 ms
WhereSelect -- mod: 6  result: 9999999, time: 480 ms
Select -- mod: 6  result 9999999, time: 391 ms
Sum -- mod: 6  result: 9999999, time: 387 ms
-------------
Where -- mod: 7 result: 8571428, time: 489 ms
WhereSelect -- mod: 7  result: 8571428, time: 486 ms
Select -- mod: 7  result 8571428, time: 384 ms
Sum -- mod: 7  result: 8571428, time: 381 ms
-------------
Where -- mod: 8 result: 8749999, time: 494 ms
WhereSelect -- mod: 8  result: 8749999, time: 488 ms
Select -- mod: 8  result 8749999, time: 386 ms
Sum -- mod: 8  result: 8749999, time: 373 ms
-------------
Where -- mod: 9 result: 9999999, time: 497 ms
WhereSelect -- mod: 9  result: 9999999, time: 494 ms
Select -- mod: 9  result 9999999, time: 386 ms
Sum -- mod: 9  result: 9999999, time: 371 ms

নিম্নলিখিত বাস্তবায়নের জন্য:

result = source.Where(x => x.IsValid).Sum(x => x.Value);
result = source.Select(x => x.IsValid ? x.Value : 0).Sum();
result = source.Sum(x => x.IsValid ? x.Value : 0);
result = source.Where(x => x.IsValid).Select(x => x.Value).Sum();

modঅর্থ: modআইটেম থেকে প্রতি 1 অবৈধ: জন্যmod == 1 প্রতিটি আইটেমের জন্য অবৈধ, mod == 2বিজোড় আইটেমগুলি অবৈধ, ইত্যাদি সংগ্রহের মধ্যে 10000000আইটেম রয়েছে ।

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

এবং 100000000আইটেমগুলি সহ সংগ্রহের ফলাফল :

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

আপনি দেখতে পাচ্ছেন, Selectএবং Sumফলাফলগুলি সমস্ত modমান জুড়ে বেশ সামঞ্জস্যপূর্ণ । তবে whereএবং where+ selectহয় না।


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

6

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

আমার এক বন্ধু পরামর্শ দিয়েছিল যে ওভারফ্লো চেকের কারণে যোগফল 0 টি তীব্র পারফরম্যান্স জরিমানার কারণ হতে পারে। এটি যাচাই না করা প্রসঙ্গে কীভাবে সম্পাদন করবে তা দেখতে আকর্ষণীয় হবে।


কিছু পরীক্ষা uncheckedএটির জন্য একটি ক্ষুদ্র, ক্ষুদ্রতর কিছুটা আরও ভাল করে তোলে Select
ইটনাটালি

কেউ যদি চেক না করে পরীক্ষা করতে পারে তবে স্ট্যাকের নীচে নামার পদ্ধতিগুলি বা কেবল শীর্ষ স্তরের অপারেশনগুলিকে প্রভাবিত করে?
স্টিলগার

1
@ স্টিলগার এটি কেবল শীর্ষ স্তরের ক্ষেত্রেই প্রযোজ্য।
ব্র্যাঙ্কো দিমিত্রিজেভিক

সুতরাং সম্ভবত আমাদের চেক না করা সমষ্টিটি প্রয়োগ করতে হবে এবং এটি এইভাবে চেষ্টা করতে হবে।
স্টিলগার

5

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

static void Main(string[] args)
        {
            int total = 10000000;
            Random r = new Random();
            var list = Enumerable.Range(0, total).Select(i => r.Next(0, 5)).ToList();
            for (int i = 0; i < 4000000; i++)
                list[i] = 10;

            var sw = new Stopwatch();
            sw.Start();

            int sum = 0;

            sum = list.Where(i => i < 10).Select(i => i).Sum();            

            sw.Stop();
            Console.WriteLine(sw.ElapsedMilliseconds);

            sw.Reset();
            sw.Start();
            sum = list.Select(i => i).Sum();            

            sw.Stop();

            Console.WriteLine(sw.ElapsedMilliseconds);
        }

আপনি কি এর অধীন দশকে ত্যাগ করবেন না বলেই তা হতে পারে না Select?
ইটনাটালি

3
ডিবাগ চালানো অকেজো।
মার্সিনজুরাজেক

1
@ মার্সিনজুরাসেকেক স্পষ্টতই। সত্যই বলতে
চাইছিলাম

@ ইটস নোটলি এটাই কথা। আমার কাছে মনে হয় যে একমাত্র উপায় যেখানে + সিলেক্ট হয়ে যায় যখন সিলেক্ট করা যায় তখন যেখানে আইটেমের সংখ্যক পরিমাণ যোগ করা যায় সেখানে ফিল্টার করা হয়।
ডেভিডএন

2
এটিই মূলত আমার প্রশ্নের বক্তব্য। তারা প্রায় 60% টাই করে, যেমন এই নমুনাটি করে। প্রশ্নটি কেন, যার উত্তর এখানে দেওয়া হয়নি।
ইটনাটালি

4

আপনার যদি গতির প্রয়োজন হয় তবে কেবল একটি সরল লুপ করা সম্ভবত আপনার সেরা বাজি। এবং করা এর forচেয়ে ভাল হতে পারে foreach(ধরে নেওয়া আপনার সংগ্রহটি অবশ্যই এলোমেলো-অ্যাক্সেস)।

10% উপাদান অবৈধ হওয়ার সাথে আমি যে সময় পেয়েছি তা এখানে:

Where + Select + Sum:   257
Select + Sum:           253
foreach:                111
for:                    61

এবং 90% অবৈধ উপাদান সহ:

Where + Select + Sum:   177
Select + Sum:           247
foreach:                105
for:                    58

এবং এখানে আমার মানদণ্ডের কোডটি ...

public class MyClass {
    public int Value { get; set; }
    public bool IsValid { get; set; }
}

class Program {

    static void Main(string[] args) {

        const int count = 10000000;
        const int percentageInvalid = 90;

        var rnd = new Random();
        var myCollection = new List<MyClass>(count);
        for (int i = 0; i < count; ++i) {
            myCollection.Add(
                new MyClass {
                    Value = rnd.Next(0, 50),
                    IsValid = rnd.Next(0, 100) > percentageInvalid
                }
            );
        }

        var sw = new Stopwatch();
        sw.Restart();
        int result1 = myCollection.Where(mc => mc.IsValid).Select(mc => mc.Value).Sum();
        sw.Stop();
        Console.WriteLine("Where + Select + Sum:\t{0}", sw.ElapsedMilliseconds);

        sw.Restart();
        int result2 = myCollection.Select(mc => mc.IsValid ? mc.Value : 0).Sum();
        sw.Stop();
        Console.WriteLine("Select + Sum:\t\t{0}", sw.ElapsedMilliseconds);
        Debug.Assert(result1 == result2);

        sw.Restart();
        int result3 = 0;
        foreach (var mc in myCollection) {
            if (mc.IsValid)
                result3 += mc.Value;
        }
        sw.Stop();
        Console.WriteLine("foreach:\t\t{0}", sw.ElapsedMilliseconds);
        Debug.Assert(result1 == result3);

        sw.Restart();
        int result4 = 0;
        for (int i = 0; i < myCollection.Count; ++i) {
            var mc = myCollection[i];
            if (mc.IsValid)
                result4 += mc.Value;
        }
        sw.Stop();
        Console.WriteLine("for:\t\t\t{0}", sw.ElapsedMilliseconds);
        Debug.Assert(result1 == result4);

    }

}

বিটিডাব্লু, আমি স্টিলগার এর অনুমানের সাথে একমত : আপনার দুটি মামলার আপেক্ষিক গতি অবৈধ আইটেমের শতাংশের উপর নির্ভর করে, কেবলমাত্র কারণ যেখানে কাজের পরিমাণ Sum"যেখানে" ক্ষেত্রে পরিবর্তিত হয়।


1

বর্ণনার মাধ্যমে ব্যাখ্যা করার চেষ্টা করার পরিবর্তে, আমি আরও গাণিতিক পদ্ধতির গ্রহণ করব।

নীচের কোডটি দেওয়া হয়েছে যা লিনকুই অভ্যন্তরীণভাবে করছে তা আনুমানিক হওয়া উচিত, আপেক্ষিক ব্যয়গুলি নিম্নরূপ:
কেবল নির্বাচন করুন:Nd + Na
যেখানে + নির্বাচন করুন:Nd + Md + Ma

তারা কখন যে পয়েন্টটি অতিক্রম করবে তা নির্ধারণ করার জন্য আমাদের কিছুটা বীজগণিত করতে হবে:
Nd + Md + Ma = Nd + Na => M(d + a) = Na => (M/N) = a/(d+a)

এর অর্থ কী তা হল যে প্রতিসারণের পয়েন্ট 50% এ যাওয়ার জন্য, একটি প্রতিনিধি আহ্বানের ব্যয়টি মোটামুটি যোগের ব্যয়ের সমান হতে হবে। যেহেতু আমরা জানি যে আসল প্রতিস্থাপনের পয়েন্টটি প্রায় at০% ছিল, তাই আমরা পিছনের দিকে কাজ করতে পারি এবং নির্ধারণ করতে পারি যে @ ইটস নোটালির জন্য একটি ডেলিগেটের অনুরোধের ব্যয়টি আসলে প্রায় 2/3 ব্যয় হয়েছিল যা অবাক করার মতো, তবে এটিই ছিল তার সংখ্যা বলে।

static void Main(string[] args)
{
    var set = Enumerable.Range(1, 10000000)
                        .Select(i => new MyClass {Value = i, IsValid = i%2 == 0})
                        .ToList();

    Func<MyClass, int> select = i => i.IsValid ? i.Value : 0;
    Console.WriteLine(
        Sum(                        // Cost: N additions
            Select(set, select)));  // Cost: N delegate
    // Total cost: N * (delegate + addition) = Nd + Na

    Func<MyClass, bool> where = i => i.IsValid;
    Func<MyClass, int> wSelect = i => i.Value;
    Console.WriteLine(
        Sum(                        // Cost: M additions
            Select(                 // Cost: M delegate
                Where(set, where),  // Cost: N delegate
                wSelect)));
    // Total cost: N * delegate + M * (delegate + addition) = Nd + Md + Ma
}

// Cost: N delegate calls
static IEnumerable<T> Where<T>(IEnumerable<T> set, Func<T, bool> predicate)
{
    foreach (var mc in set)
    {
        if (predicate(mc))
        {
            yield return mc;
        }
    }
}

// Cost: N delegate calls
static IEnumerable<int> Select<T>(IEnumerable<T> set, Func<T, int> selector)
{
    foreach (var mc in set)
    {
        yield return selector(mc);
    }
}

// Cost: N additions
static int Sum(IEnumerable<int> set)
{
    unchecked
    {
        var sum = 0;
        foreach (var i in set)
        {
            sum += i;
        }

        return sum;
    }
}

0

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

আসুন আমরা ধরে নিই যে এখানে nমোট উপাদান এবং mবৈধ উপাদান রয়েছে।

Sumফাংশন বেশ সহজ। এটি কেবল গণকের মাধ্যমে লুপ করে: http://typedescriptor.net/browse/mebers/367300- সিস্টেম.লিনিক.আনুনেবল.সুমুআইআই সংখ্যাযুক্ত 6060)

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

যেহেতু পুনরাবৃত্তিগুলি একই, লুপগুলি একই। লুপগুলির শরীরে পার্থক্য কেবল।

এই ল্যাম্বডাসের দেহের খুব মিল রয়েছে। যেখানে ধারাটি ক্ষেত্রের মান প্রদান করে এবং ত্রৈমাসিক প্রাকটিক্টটি একটি ক্ষেত্রের মানও দেয়। নির্বাচিত ধারাটি একটি ক্ষেত্রের মান প্রদান করে এবং টের্নারি অপারেটরের দুটি শাখা হয় ক্ষেত্রের মান বা ধ্রুবক ফেরত দেয়। সম্মিলিত নির্বাচনের ধারাটিতে একটি টেরিনারি অপারেটর হিসাবে শাখা রয়েছে, তবে হোয়াইটলেকটি শাখাটি ব্যবহার করেMoveNext

তবে এই সমস্ত অপারেশন মোটামুটি সস্তা। এখন পর্যন্ত সবচেয়ে ব্যয়বহুল অপারেশনটি শাখা, যেখানে একটি ভুল পূর্বাভাস আমাদের দিতে হবে।

এখানে অন্য ব্যয়বহুল অপারেশন হয় Invoke । ব্র্যাঙ্কো দিমিত্রিজেভিচ যেমন দেখিয়েছেন তেমন কোনও মূল্য যুক্ত করার চেয়ে কোনও ক্রিয়াকলাপ চালানো বেশ খানিকটা সময় নেয়।

এছাড়াও ওজন হ'ল চেক জমে থাকা Sum । প্রসেসরের যদি গাণিতিক ওভারফ্লো পতাকা না থাকে তবে এটিও পরীক্ষা করা ব্যয়বহুল হতে পারে।

অতএব, আকর্ষণীয় ব্যয়গুলি হ'ল:

  1. ( n+ m) * ডাকা + m*checked+=
  2. n* দাওয়াত + n*checked+=

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

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


@ It'sNotALie। আমি মনে করি না কারও ভুল ফল হয়েছে। আমি শুধু কিছু জিনিস ব্যাখ্যা করতে পারিনি। আমি ধরে নিয়েছিলাম যে ইনভোকের ব্যয়টি + = এর চেয়ে অনেক বেশি হ'ল তবে ধারণা করা যায় যে তারা হার্ডওয়্যার অপ্টিমাইজেশনের উপর নির্ভর করে আরও কাছাকাছি হতে পারে।
জন সেং
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.