লিনকিউ এমনভাবে প্রয়োগ করে কী কী লাভ হয়েছিল যাতে ফলাফলগুলি ক্যাশে হয় না?


20

এটি লিনকিউ ব্যবহার করে যারা পা ভিজিয়ে চলেছে তাদের পক্ষে এটি একটি পরিচিত সমস্যা:

public class Program
{
    public static void Main()
    {
        IEnumerable<Record> originalCollection = GenerateRecords(new[] {"Jesse"});
        var newCollection = new List<Record>(originalCollection);

        Console.WriteLine(ContainTheSameSingleObject(originalCollection, newCollection));
    }

    private static IEnumerable<Record> GenerateRecords(string[] listOfNames)
    {
        return listOfNames.Select(x => new Record(Guid.NewGuid(), x));
    }

    private static bool ContainTheSameSingleObject(IEnumerable<Record>
            originalCollection, List<Record> newCollection)
    {
        return originalCollection.Count() == 1 && newCollection.Count() == 1 &&
                originalCollection.Single().Id == newCollection.Single().Id;
    }

    private class Record
    {
        public Guid Id { get; }
        public string SomeValue { get; }

        public Record(Guid id, string someValue)
        {
            Id = id;
            SomeValue = someValue;
        }
    }
}

এটি "মিথ্যা" মুদ্রণ করবে, কারণ প্রতিটি নামের জন্য মূল সংগ্রহটি তৈরি করার জন্য সরবরাহ করা, নির্বাচিত ফাংশনটি Recordপুনরায় মূল্যায়ন করতে থাকে এবং ফলস্বরূপ বস্তুটি নতুনভাবে তৈরি হয়। এটি ঠিক করতে, ToListশেষে একটি সাধারণ কল যুক্ত করা যেতে পারে GenerateRecords

মাইক্রোসফ্ট এইভাবে এটি প্রয়োগ করে কোন লাভের আশা করেছিল?

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

একবার লিনকিউ দ্বারা প্রদত্ত কোনও সংগ্রহের কোনও প্রদত্ত সদস্যকে মূল্যায়ন করা গেলে, কোনও অভ্যন্তরীণ রেফারেন্স / অনুলিপি না রেখে, বরং একই ফলাফলটিকে পুনরায় গণনা করে ডিফল্ট আচরণ হিসাবে কী সুবিধা দেওয়া হয়?

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

এতে কী সুবিধা রয়েছে এবং মাইক্রোসফ্ট কেন এই আপাতদৃষ্টিতে খুব ইচ্ছাকৃত সিদ্ধান্ত নিয়েছিল?


1
আপনার জেনারেটরেকর্ডস () পদ্ধতিতে কেবলমাত্র টলিস্ট () কল করুন। return listOfNames.Select(x => new Record(Guid.NewGuid(), x)).ToList(); এটি আপনাকে আপনার "ক্যাশেড অনুলিপি" দেয়। সমস্যা সমাধান.
রবার্ট হার্ভে

1
আমি জানি, তবে আমি ভাবছিলাম যে তারা কেন এটি প্রথম স্থানে প্রয়োজনীয় করবে।
Panzercrisis

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

আমি শপথ করে বলতে পারি যে আমি গত প্রায় 6 মাসে এখানে প্রায় অনুরূপ বাক্যযুক্ত প্রশ্নটি পড়েছি তবে এখন এটি সন্ধান করছি না। নিকটস্থ আমি জানতে পারেন Stackoverflow উপর 2016 থেকে ছিল: stackoverflow.com/q/37437893/391656
Mr.Mindor

29
আমাদের একটি সমাপ্তির নীতি ছাড়াই ক্যাশের নাম রয়েছে: "মেমরি ফাঁস"। আমাদের একটি অবৈধ নীতি ছাড়াই ক্যাশের নাম রয়েছে: "বাগ ফার্ম"। আপনি যদি সর্বদা সঠিক সমাপ্তির মেয়াদ এবং অবৈধ নীতি প্রস্তাব করতে যাচ্ছেন না যা প্রতিটি সম্ভাব্য লিনকিউ ক্যোয়ারির জন্য কাজ করে তবে আপনার প্রশ্নটি নিজেই উত্তর দেয়।
এরিক লিপার্ট

উত্তর:


51

লিনকিউ এমনভাবে প্রয়োগ করে কী কী লাভ হয়েছিল যাতে ফলাফলগুলি ক্যাশে হয় না?

ফলাফলগুলি ক্যাচ করা সহজভাবে সবার জন্য কাজ করে না। যতক্ষণ না আপনার কাছে ক্ষুদ্র পরিমাণের ডেটা থাকে, দুর্দান্ত। তোমার জন্য ভালো. তবে যদি আপনার ডেটা আপনার র‌্যামের চেয়ে বড় হয়?

এটি লিনকিউয়ের সাথে কিছুই করার নেই, তবে IEnumerable<T>সাধারণভাবে ইন্টারফেসের সাথে ।

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

আপনি নিজের ক্রম কলিং .ToList()বা .ToArray()এটির কলকে মেশিনাইজেশন করে যা আপনি ক্যাশে করতে চান তা সহজেই ক্যাশে করতে পারেন । কিন্তু আমাদের মধ্যে যারা না না এটা ক্যাশে করতে চান, আমরা একটি সুযোগ আছে না তাই না।

এবং সম্পর্কিত নোটে: আপনি কীভাবে নিম্নলিখিত ক্যাশে করবেন?

IEnumerable<int> AllTheZeroes()
{
    while(true) yield return 0;
}

তুমি পার না. সে কারণেই IEnumerable<T>এটি বিদ্যমান।


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

23
@ রবার্টহারভে এটি সত্য, আমি কেবল বুঝতে পেরেছিলাম যে এটি শূন্যের অন্তহীন স্রোত যখন বোঝার কোনও যুক্তি নেই তখনই এটি জিরোদের অন্তহীন প্রবাহ।
এনভিগেট

2
int i=1; while(true) { i++; yield fib(i); }
রবার্ট হার্ভে 16

2
আমি যে উদাহরণটির কথা ভাবছিলাম তা হ'ল Enumerable.Range(1,int.MaxValue)- এটি কতটা স্মৃতি ব্যবহার করতে চলেছে তার নিচু কাজটি করা খুব সহজ।
ক্রিস

4
অন্যান্য জিনিস আমি লাইন বরাবর দেখেছি while (true) return ...ছিল while (true) return _random.Next();এলোমেলো সংখ্যার অসীম প্রবাহ তৈরি করা।
ক্রিস

24

মাইক্রোসফ্ট এইভাবে এটি প্রয়োগ করে কোন লাভের আশা করেছিল?

শুদ্ধি? আমি বলতে চাইছি, মূল সংখ্যাটি কলগুলির মধ্যে পরিবর্তিত হতে পারে। এটি ক্যাচিংয়ের ফলে ভুল ফলাফল পাওয়া যাবে এবং পুরোটি খুলবে "কখন / কীভাবে আমি সেই ক্যাশেটি অবৈধ করব?" কৃমি হতে পারে।

এবং যদি আপনি বিবেচনা LINQ মূলত তথ্য সূত্র (সত্তা ফ্রেমওয়ার্ক, অথবা এসকিউএল সরাসরি মত) LINQ করতে একটি উপায় হিসেবে পরিকল্পনা করা হয়েছিল, গণনীয় ছিল ডাটাবেস কি যে এর থেকে পরিবর্তন করতে যাচ্ছেন না

তার উপরে, একক দায়িত্বের নীতিগত উদ্বেগ রয়েছে। এমন কোয়েরি কোড তৈরি করা যেগুলি কোয়েরি তৈরি করে এবং ক্যাশে তৈরি করে তারপরে ক্যাশে তৈরি করে তবে ক্যাশে মুছে ফেলা তার চেয়ে অনেক সহজ।


3
এটি অবশ্যই উল্লেখযোগ্য যে এটি ICollectionবিদ্যমান, এবং সম্ভবত ওপি IEnumerableআচরণের প্রত্যাশার সাথে আচরণ করে
ক্যালথ

যদি আপনি একটি খোলামেলা ডাটাবেস কার্সারটি পড়ার জন্য IEnumerable <T> ব্যবহার করেন তবে আপনি যদি এসিডি লেনদেনের সাথে একটি ডাটাবেস ব্যবহার করেন তবে আপনার ফলাফলগুলি পরিবর্তন করা উচিত নয়।
ডগ

4

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


4

আরেকটি কারণ যা উল্লেখ করা হয়নি তা হ'ল, আবর্জনার মধ্যবর্তী ফলাফল তৈরি না করেই বিভিন্ন ফিল্টার এবং রূপান্তরকে সম্মিলিত করার সম্ভাবনা।

উদাহরণস্বরূপ এটি নিন:

cars.Where(c => c.Year > 2010)
.Select(c => new { c.Model, c.Year, c.Color })
.GroupBy(c => c.Year);

যদি লিনকিউ পদ্ধতিগুলি তাত্ক্ষণিকভাবে ফলাফলগুলি গণনা করে, তবে আমাদের কাছে 3 টি সংগ্রহ থাকবে:

  • যেখানে ফলাফল
  • ফলাফল নির্বাচন করুন
  • গ্রুপপত্রে ফলাফল

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

যদি এই ফলাফলগুলির কোনও সংরক্ষণের প্রয়োজন হয়, তবে সমাধানটি সহজ: কলগুলি আলাদা করে ভেঙে কল .ToList()করুন এবং তাদের পরিবর্তনশীল হিসাবে সংরক্ষণ করুন।


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


3

মূলত, এই কোড - Guid.NewGuid ()একটি Selectবিবৃতিতে একটি অভ্যন্তর স্থাপন - অত্যন্ত সন্দেহজনক। এটি অবশ্যই কোনও ধরণের কোড গন্ধ!

তত্ত্বগতভাবে, আমরা অগত্যা কোনও Selectনতুন ডেটা তৈরির জন্য একটি বিবৃতি প্রত্যাশা করব না তবে বিদ্যমান ডেটা পুনরুদ্ধার করব। যদিও নির্বাচনের পক্ষে একাধিক উত্স থেকে ডেটা যোগ করার জন্য বিভিন্ন আকারের যুক্ত সামগ্রী যুক্ত করতে বা অতিরিক্ত কলামগুলি গণনা করা যুক্তিসঙ্গত, আমরা এখনও এটি কার্যকরী এবং খাঁটি আশা করতে পারি। NewGuid ()ভিতরে োকানো এটিকে অ-কার্যক্ষম এবং অ-খাঁটি করে তোলে।

ডেটা তৈরির বিষয়টি সিলেক্ট করে আলাদাভাবে ছড়িয়ে দেওয়া যেতে পারে এবং কোনও প্রকারের ক্রিয়াকলাপ তৈরি করা যেতে পারে, যাতে নির্বাচনটি খাঁটি এবং পুনরায় ব্যবহারযোগ্য হতে পারে, অন্যথায় নির্বাচনটি কেবল একবার করে আবৃত / সুরক্ষিত করা উচিত - এটি হয় .ToList ()প্রস্তাব।

তবে, স্পষ্ট করে বললে, বিষয়টি আমার মনে হয় নির্বাচনের ভিতরে ক্যাশেগের অভাবের চেয়ে সৃষ্টির মিশ্রণ। NewGuid()নির্বাচনের ভিতরে থাকাটি আমার কাছে প্রোগ্রামিং মডেলের একটি অনুপযুক্ত মিশ্রণ বলে মনে হয়।


0

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

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

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