আমি টোকলুকআপের আগে অতিরিক্ত টোআরে রাখি তা কেন দ্রুত?


10

আমাদের কাছে একটি স্বল্প পদ্ধতি রয়েছে যা .csv ফাইলটিকে একটি দেখার জন্য বিশ্লেষণ করে:

ILookup<string, DgvItems> ParseCsv( string fileName )
{
    var file = File.ReadAllLines( fileName );
    return file.Skip( 1 ).Select( line => new DgvItems( line ) ).ToLookup( item => item.StocksID );
}

এবং ডিজিভিটেমসের সংজ্ঞা:

public class DgvItems
{
    public string DealDate { get; }

    public string StocksID { get; }

    public string StockName { get; }

    public string SecBrokerID { get; }

    public string SecBrokerName { get; }

    public double Price { get; }

    public int BuyQty { get; }

    public int CellQty { get; }

    public DgvItems( string line )
    {
        var split = line.Split( ',' );
        DealDate = split[0];
        StocksID = split[1];
        StockName = split[2];
        SecBrokerID = split[3];
        SecBrokerName = split[4];
        Price = double.Parse( split[5] );
        BuyQty = int.Parse( split[6] );
        CellQty = int.Parse( split[7] );
    }
}

এবং আমরা দেখতে পেয়েছি যে আমরা যদি এর ToArray()আগে একটি অতিরিক্ত যোগ করি ToLookup():

static ILookup<string, DgvItems> ParseCsv( string fileName )
{
    var file = File.ReadAllLines( fileName  );
    return file.Skip( 1 ).Select( line => new DgvItems( line ) ).ToArray().ToLookup( item => item.StocksID );
}

পরবর্তীটি উল্লেখযোগ্যভাবে দ্রুত হয়। আরও সুনির্দিষ্টভাবে, ১.৪ মিলিয়ন লাইনের সাহায্যে পরীক্ষার ফাইলটি ব্যবহার করার সময়, প্রাক্তনটি প্রায় ৪.৩ সেকেন্ড এবং দ্বিতীয়টি প্রায় ৩ সেকেন্ড সময় নেয়।

আমি প্রত্যাশা করি ToArray()অতিরিক্ত সময় নেওয়া উচিত তাই উত্তরোত্তরটি কিছুটা ধীর হওয়া উচিত। এটি আসলে দ্রুত কেন?


অতিরিক্ত তথ্য:

  1. আমরা এই সমস্যাটি খুঁজে পেয়েছি কারণ এখানে আরও একটি পদ্ধতি রয়েছে যা একই .csv ফাইলটিকে বিভিন্ন ফর্ম্যাটে পার্স করে এবং এটি প্রায় 3 সেকেন্ড সময় নেয় তাই আমরা মনে করি যে এটি 3 সেকেন্ডের মধ্যে একই জিনিসটি করতে সক্ষম হবে।

  2. মূল ডেটা টাইপ হয় Dictionary<string, List<DgvItems>>এবং মূল কোড লিনক ব্যবহার করে না এবং ফলাফলটিও একই রকম।


বেঞ্চমার্কডটনেট পরীক্ষার শ্রেণি:

public class TestClass
{
    private readonly string[] Lines;

    public TestClass()
    {
        Lines = File.ReadAllLines( @"D:\20110315_Random.csv" );
    }

    [Benchmark]
    public ILookup<string, DgvItems> First()
    {
        return Lines.Skip( 1 ).Select( line => new DgvItems( line ) ).ToArray().ToLookup( item => item.StocksID );
    }

    [Benchmark]
    public ILookup<string, DgvItems> Second()
    {
        return Lines.Skip( 1 ).Select( line => new DgvItems( line ) ).ToLookup( item => item.StocksID );
    }
}

ফলাফল:

| Method |    Mean |    Error |   StdDev |
|------- |--------:|---------:|---------:|
|  First | 2.530 s | 0.0190 s | 0.0178 s |
| Second | 3.620 s | 0.0217 s | 0.0203 s |

আমি মূল কোডে অন্য একটি পরীক্ষা বেস করেছি did দেখে মনে হচ্ছে সমস্যা লিনকের নয়।

public class TestClass
{
    private readonly string[] Lines;

    public TestClass()
    {
        Lines = File.ReadAllLines( @"D:\20110315_Random.csv" );
    }

    [Benchmark]
    public Dictionary<string, List<DgvItems>> First()
    {
        List<DgvItems> itemList = new List<DgvItems>();
        for ( int i = 1; i < Lines.Length; i++ )
        {
            itemList.Add( new DgvItems( Lines[i] ) );
        }

        Dictionary<string, List<DgvItems>> dictionary = new Dictionary<string, List<DgvItems>>();

        foreach( var item in itemList )
        {
            if( dictionary.TryGetValue( item.StocksID, out var list ) )
            {
                list.Add( item );
            }
            else
            {
                dictionary.Add( item.StocksID, new List<DgvItems>() { item } );
            }
        }

        return dictionary;
    }

    [Benchmark]
    public Dictionary<string, List<DgvItems>> Second()
    {
        Dictionary<string, List<DgvItems>> dictionary = new Dictionary<string, List<DgvItems>>();
        for ( int i = 1; i < Lines.Length; i++ )
        {
            var item = new DgvItems( Lines[i] );

            if ( dictionary.TryGetValue( item.StocksID, out var list ) )
            {
                list.Add( item );
            }
            else
            {
                dictionary.Add( item.StocksID, new List<DgvItems>() { item } );
            }
        }

        return dictionary;
    }
}

ফলাফল:

| Method |    Mean |    Error |   StdDev |
|------- |--------:|---------:|---------:|
|  First | 2.470 s | 0.0218 s | 0.0182 s |
| Second | 3.481 s | 0.0260 s | 0.0231 s |

2
আমি পরীক্ষার কোড / পরিমাপের বিষয়ে অত্যন্ত সন্দেহ করি। সময় গণনা করে দয়া করে কোডটি পোস্ট করুন
এর্নো

1
আমার ধারণা হ'ল .ToArray()কল ছাড়াই কলটি কল করার .Select( line => new DgvItems( line ) )আগে একটি মূল সংখ্যা ফেরত দেয় ToLookup( item => item.StocksID )। এবং একটি নির্দিষ্ট উপাদান সন্ধান করা অ্যারের চেয়ে আইনিম্যারেবল ব্যবহার করা আরও খারাপ। একটি অ্যারে রূপান্তর এবং সম্ভবত একটি তাত্পর্যপূর্ণ ব্যবহার না করে দেখুন সম্পাদন করা দ্রুত।
কিম্বাউদি

2
পার্শ্ব দ্রষ্টব্য: রাখুন var file = File.ReadLines( fileName );- এর ReadLinesপরিবর্তে ReadAllLinesএবং আপনার কোড সম্ভবত দ্রুততর হবে
দিমিত্রি বাইচেনকো

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

1
কেন জানি এটিকে ডাউনটায়েট দেওয়া হয়েছিল - আমি মনে করি এটি একটি ভাল প্রশ্ন।
রুফাস এল

উত্তর:


2

আমি নীচের সরলীকৃত কোড সহ সমস্যাটির প্রতিলিপি করতে সক্ষম হয়েছি:

var lookup = Enumerable.Range(0, 2_000_000)
    .Select(i => ( (i % 1000).ToString(), i.ToString() ))
    .ToArray() // +20% speed boost
    .ToLookup(x => x.Item1);

এটি গুরুত্বপূর্ণ যে তৈরি টিপলের সদস্যরা স্ট্রিং থাকে। .ToString()উপরের কোড থেকে দু'টিকে সরিয়ে ফেলার সুবিধাটি হ্রাস করে ToArray। .NET ফ্রেমওয়ার্কটি নেট কোরের থেকে কিছুটা আলাদা আচরণ করে, যেহেতু .ToString()পর্যবেক্ষণের পার্থক্য দূর করার জন্য এটি কেবল প্রথমটিকে সরিয়ে ফেলার জন্য এটি যথেষ্ট ।

কেন এমন হয় আমার কোনও ধারণা নেই।


আপনি কোন কাঠামোর সাথে এটি নিশ্চিত করেছেন? আমি নেট নেট ফ্রেমওয়ার্ক ৪.7.২ ব্যবহার করে কোনও পার্থক্য দেখতে পারছি না
ম্যাগনাস

@ ম্যাগনাস। নেট ফ্রেমওয়ার্ক 4.8 (ভিএস 2019, রিলিজ বিল্ড)
থিওডর জৌলিয়াস

প্রাথমিকভাবে আমি পর্যবেক্ষণের পার্থক্যটি অতিরঞ্জিত করেছিলাম। এটি নেট কোরে প্রায় 20%, এবং নেট ফ্রেমওয়ার্কের প্রায় 10%।
থিওডর জৌলিয়াস

1
ভাল repro। কেন এমনটি হয় তার আমার কোনও নির্দিষ্ট জ্ঞান নেই এবং এটি বের করার সময় নেই, তবে আমার অনুমানটি হ'ল যে ToArrayবা ToListতথ্য উপাত্তকে সংকীর্ণ স্মৃতিতে রাখতে বাধ্য করে; পাইপলাইনে একটি নির্দিষ্ট পর্যায়ে জোর করে এমনটি করা, যদিও এতে ব্যয় যুক্ত হয়, পরবর্তী ক্রিয়াকলাপটি কম প্রসেসরের ক্যাশে মিস করতে পারে; প্রসেসর ক্যাশে মিস মিস আশ্চর্যজনকভাবে ব্যয়বহুল।
এরিক লিপার্ট
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.