সংকলিত সি # ল্যাম্বদা এক্সপ্রেশন পারফরম্যান্স


91

একটি সংগ্রহের উপর নিম্নলিখিত সহজ হেরফের বিবেচনা করুন:

static List<int> x = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var result = x.Where(i => i % 2 == 0).Where(i => i > 5);

এখন এক্সপ্রেশন ব্যবহার করা যাক। নিম্নলিখিত কোডটি মোটামুটি সমতুল্য:

static void UsingLambda() {
    Func<IEnumerable<int>, IEnumerable<int>> lambda = l => l.Where(i => i % 2 == 0).Where(i => i > 5);
    var t0 = DateTime.Now.Ticks;
    for (int j = 1; j < MAX; j++) 
        var sss = lambda(x).ToList();

    var tn = DateTime.Now.Ticks;
    Console.WriteLine("Using lambda: {0}", tn - t0);
}

তবে আমি অভিব্যক্তিটি অন ফ্লাইটে তৈরি করতে চাই, সুতরাং এখানে একটি নতুন পরীক্ষা দেওয়া হল:

static void UsingCompiledExpression() {
    var f1 = (Expression<Func<IEnumerable<int>, IEnumerable<int>>>)(l => l.Where(i => i % 2 == 0));
    var f2 = (Expression<Func<IEnumerable<int>, IEnumerable<int>>>)(l => l.Where(i => i > 5));
    var argX = Expression.Parameter(typeof(IEnumerable<int>), "x");
    var f3 = Expression.Invoke(f2, Expression.Invoke(f1, argX));
    var f = Expression.Lambda<Func<IEnumerable<int>, IEnumerable<int>>>(f3, argX);

    var c3 = f.Compile();

    var t0 = DateTime.Now.Ticks;
    for (int j = 1; j < MAX; j++) 
        var sss = c3(x).ToList();

    var tn = DateTime.Now.Ticks;
    Console.WriteLine("Using lambda compiled: {0}", tn - t0);
}

অবশ্যই এটি ঠিক উপরের মত নয়, তাই ন্যায়বিচারের জন্য, আমি প্রথমটিকে কিছুটা সংশোধন করেছি:

static void UsingLambdaCombined() {
    Func<IEnumerable<int>, IEnumerable<int>> f1 = l => l.Where(i => i % 2 == 0);
    Func<IEnumerable<int>, IEnumerable<int>> f2 = l => l.Where(i => i > 5);
    Func<IEnumerable<int>, IEnumerable<int>> lambdaCombined = l => f2(f1(l));
    var t0 = DateTime.Now.Ticks;
    for (int j = 1; j < MAX; j++) 
        var sss = lambdaCombined(x).ToList();

    var tn = DateTime.Now.Ticks;
    Console.WriteLine("Using lambda combined: {0}", tn - t0);
}

এখন MAX = 100000, VS2008, ডিবাগিং অন এর ফলাফল আসে:

Using lambda compiled: 23437500
Using lambda:           1250000
Using lambda combined:  1406250

এবং ডিবাগিং বন্ধ সহ:

Using lambda compiled: 21718750
Using lambda:            937500
Using lambda combined:  1093750

অবাক । সংকলিত এক্সপ্রেশনটি অন্যান্য বিকল্পগুলির চেয়ে প্রায় 17x ধীর। এখন এখানে প্রশ্নগুলি আসে:

  1. আমি কি অ-সমমানের ভাবের তুলনা করছি?
  2. .NET সংকলিত অভিব্যক্তিটি "অনুকূলিতকরণ" করার কোনও ব্যবস্থা আছে?
  3. আমি কীভাবে একই চেইন কলটি l.Where(i => i % 2 == 0).Where(i => i > 5);অগ্রগামীভাবে প্রকাশ করব ?

আরও কিছু পরিসংখ্যান। ভিজ্যুয়াল স্টুডিও 2010, ডিবাগিং চালু, অপ্টিমাইজেশন বন্ধ:

Using lambda:           1093974
Using lambda compiled: 15315636
Using lambda combined:   781410

ডিবাগিং চালু, অপ্টিমাইজেশন চালু:

Using lambda:            781305
Using lambda compiled: 15469839
Using lambda combined:   468783

ডিবাগিং বন্ধ, অপ্টিমাইজেশন চালু:

Using lambda:            625020
Using lambda compiled: 14687970
Using lambda combined:   468765

নতুন চমক। ভিএস2008 (সি # 3) থেকে ভিএস 2010 (সি # 4) এ স্যুইচ করা UsingLambdaCombinedদেশীয় ল্যাম্বডারের চেয়ে দ্রুততর হয়।


ঠিক আছে, আমি লম্বড্ডা সংকলিত পারফরম্যান্সটির প্রস্থের চেয়ে আরও বেশি করে উন্নত করার একটি উপায় খুঁজে পেয়েছি। এই হল বকশিষ; প্রোফাইল চালানোর পরে, 92% সময় ব্যয় হয়:

System.Reflection.Emit.DynamicMethod.CreateDelegate(class System.Type, object)

হুমমম ... কেন এটি প্রতিটি পুনরাবৃত্তিতে একটি নতুন প্রতিনিধি তৈরি করছে? আমি নিশ্চিত নই, তবে সমাধানটি পৃথক পোস্টে অনুসরণ করবে।


4
এই সময়গুলি কি ভিজ্যুয়াল স্টুডিওতে চলছে? যদি তা হয় তবে রিলিজ মোড বিল্ড ব্যবহার করে সময় পুনরাবৃত্তি করুন এবং ডিবাগিং ছাড়াই চলুন (যেমন ভিজ্যুয়াল স্টুডিওতে Ctrl + F5, অথবা কমান্ড লাইন থেকে)। এছাড়াও, Stopwatchসময়ের চেয়ে সময় ব্যবহারের জন্য বিবেচনা করুন DateTime.Now
জিম মিশেল

12
আমি জানি না কেন এটি ধীরতর, তবে আপনার মানদণ্ডের কৌশলটি খুব ভাল নয়। প্রথমে, ডেটটাইম.এখন এক সেকেন্ডের ১/6464 মাত্র সঠিক, সুতরাং আপনার পরিমাপের গোল করার ত্রুটি বড় is পরিবর্তে স্টপওয়াচ ব্যবহার করুন; এটি কয়েকটি ন্যানোসেকেন্ডে সঠিক। দ্বিতীয়ত, আপনি কোডটি (প্রথম কল) এবং পরবর্তী প্রতিটি কলকে জিট করার জন্য উভয় সময় পরিমাপ করছেন; এটি গড় ফেলে দিতে পারে। (যদিও এক্ষেত্রে এক লক্ষের এক ম্যাক্স সম্ভবত জিটের বোঝা দূর করতে যথেষ্ট, তবুও, এটির গড়পড়তা অন্তর্ভুক্ত করা একটি খারাপ অভ্যাস))
এরিক লিপার্ট

7
@ এরিক, রাউন্ডিং ত্রুটি কেবল তখনই ঘটতে পারে যদি প্রতিটি অপারেশনে ডেটটাইম.নিউজ.টিক্স ব্যবহৃত হয়, শুরু করার আগে এবং শেষের পরে, মিলিসেকেন্ড গুনগুলি পারফরম্যান্স পার্থক্য দেখানোর জন্য যথেষ্ট উচ্চ।
আকাশ কাভা

4
যদি স্টপওয়াচ ব্যবহার করে থাকেন তবে সঠিক ফলাফল নিশ্চিত করতে আমি এই নিবন্ধটি অনুসরণ করার পরামর্শ দিচ্ছি
জ্যাচ গ্রিন

4
@ এরিক, যদিও আমি সম্মত হই যে এটি সর্বাধিক সুনির্দিষ্ট পরিমাপ কৌশল উপলব্ধ নয়, আমরা পার্থক্যের মাত্রার অর্ডার সম্পর্কে কথা বলছি। MAX উল্লেখযোগ্য বিচ্যুতি হ্রাস করার জন্য যথেষ্ট বেশি।
হুগো সেরেনো ফেরেরিরা

উত্তর:


43

এমন কি হতে পারে যে অভ্যন্তরীণ ল্যাম্বডাস সংকলিত হচ্ছে না?!? ধারণার একটি প্রমাণ এখানে:

static void UsingCompiledExpressionWithMethodCall() {
        var where = typeof(Enumerable).GetMember("Where").First() as System.Reflection.MethodInfo;
        where = where.MakeGenericMethod(typeof(int));
        var l = Expression.Parameter(typeof(IEnumerable<int>), "l");
        var arg0 = Expression.Parameter(typeof(int), "i");
        var lambda0 = Expression.Lambda<Func<int, bool>>(
            Expression.Equal(Expression.Modulo(arg0, Expression.Constant(2)),
                             Expression.Constant(0)), arg0).Compile();
        var c1 = Expression.Call(where, l, Expression.Constant(lambda0));
        var arg1 = Expression.Parameter(typeof(int), "i");
        var lambda1 = Expression.Lambda<Func<int, bool>>(Expression.GreaterThan(arg1, Expression.Constant(5)), arg1).Compile();
        var c2 = Expression.Call(where, c1, Expression.Constant(lambda1));

        var f = Expression.Lambda<Func<IEnumerable<int>, IEnumerable<int>>>(c2, l);

        var c3 = f.Compile();

        var t0 = DateTime.Now.Ticks;
        for (int j = 1; j < MAX; j++)
        {
            var sss = c3(x).ToList();
        }

        var tn = DateTime.Now.Ticks;
        Console.WriteLine("Using lambda compiled with MethodCall: {0}", tn - t0);
    }

এবং এখন সময়গুলি হল:

Using lambda:                            625020
Using lambda compiled:                 14687970
Using lambda combined:                   468765
Using lambda compiled with MethodCall:   468765

পাছা! এটি কেবল দ্রুত নয়, এটি দেশীয় ল্যাম্বদার চেয়েও দ্রুত। ( স্ক্র্যাচ মাথা )


অবশ্যই উপরের কোডটি লিখতে খুব কষ্টকর। আসুন কিছু সাধারণ যাদু করা যাক:

static void UsingCompiledConstantExpressions() {
    var f1 = (Func<IEnumerable<int>, IEnumerable<int>>)(l => l.Where(i => i % 2 == 0));
    var f2 = (Func<IEnumerable<int>, IEnumerable<int>>)(l => l.Where(i => i > 5));
    var argX = Expression.Parameter(typeof(IEnumerable<int>), "x");
    var f3 = Expression.Invoke(Expression.Constant(f2), Expression.Invoke(Expression.Constant(f1), argX));
    var f = Expression.Lambda<Func<IEnumerable<int>, IEnumerable<int>>>(f3, argX);

    var c3 = f.Compile();

    var t0 = DateTime.Now.Ticks;
    for (int j = 1; j < MAX; j++) {
        var sss = c3(x).ToList();
    }

    var tn = DateTime.Now.Ticks;
    Console.WriteLine("Using lambda compiled constant: {0}", tn - t0);
}

এবং কিছু সময়, VS2010, অপ্টিমাইজেশন চালু, ডিবাগিং অফ:

Using lambda:                            781260
Using lambda compiled:                 14687970
Using lambda combined:                   468756
Using lambda compiled with MethodCall:   468756
Using lambda compiled constant:          468756

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


আমার বোধগম্যতা থেকে, যা চলছে তা C। সংকলন () পদ্ধতিটি অভ্যন্তরীণ ল্যাম্বডাসে সংকলনগুলি প্রচার করে না এবং এভাবেই স্থিরভাবে প্রার্থনা CreateDelegate। তবে সত্যই এটি বুঝতে, আমি একটি নেট গুরুর অভ্যন্তরীণ জিনিসপত্র সম্পর্কে কিছুটা মন্তব্য করতে পছন্দ করব।

এবং কেন , ওহ কেন এখন দেশীয় ল্যাম্বদার চেয়ে দ্রুত !?


4
আমি আমার নিজের উত্তর গ্রহণ করার বিষয়ে ভাবছি, যেহেতু এটিই সর্বাধিক ভোট সহ with আমার আরও কিছুক্ষণ অপেক্ষা করা উচিত?
হুগো সেরেনো ফেরেরিরা

দেশীয় ল্যাম্বডারের চেয়ে আপনার কোড দ্রুত পাওয়ার সাথে কী ঘটে থাকে সে সম্পর্কে আপনি মাইক্রোবেইনমার্কগুলি সম্পর্কে (যা আসলে জাভা-নির্দিষ্ট কিছুই নেই, নামটি সত্ত্বেও) সম্পর্কে এই পৃষ্ঠাটি একবার দেখে নিতে পারেন: Code.google.com/p/caliper/wiki / জাভামাইক্রোবেইনমার্কস
ব্লেসরব্ল্যাড

কেন গতিশীলভাবে সংকলিত লাম্বদা দ্রুততর, আমি সন্দেহ করি যে "ল্যাম্বডা ব্যবহার করা" প্রথমে চালানো হচ্ছে, কিছু কোড জেআইটি থাকার কারণে দণ্ডিত করা হচ্ছে।
ওসকার বার্গগ্রেন

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

10

সম্প্রতি আমি প্রায় একটি অভিন্ন প্রশ্ন জিজ্ঞাসা করেছি:

সংকলিত থেকে প্রতিনিধি এক্সপ্রেশন সম্পাদন

আমার জন্য সমাধান ছিল যে আমি ফোন করা উচিত নয় Compileউপর Expression, কিন্তু যে আমি কল করা উচিত CompileToMethodএটা এবং কম্পাইল Expressionএকটি থেকে staticসমাবেশ একটি গতিশীল মধ্যে পদ্ধতি।

তাই ভালো:

var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
  new AssemblyName("MyAssembly_" + Guid.NewGuid().ToString("N")), 
  AssemblyBuilderAccess.Run);

var moduleBuilder = assemblyBuilder.DefineDynamicModule("Module");

var typeBuilder = moduleBuilder.DefineType("MyType_" + Guid.NewGuid().ToString("N"), 
  TypeAttributes.Public));

var methodBuilder = typeBuilder.DefineMethod("MyMethod", 
  MethodAttributes.Public | MethodAttributes.Static);

expression.CompileToMethod(methodBuilder);

var resultingType = typeBuilder.CreateType();

var function = Delegate.CreateDelegate(expression.Type,
  resultingType.GetMethod("MyMethod"));

এটি তবে আদর্শ নয়। আমি বেশ যা ধরনের এই ঠিক প্রযোজ্য নিশ্চিত নয়, কিন্তু আমি মনে করি যে ধরনের যে প্রতিনিধি দ্বারা প্রতিনিধি দ্বারা পরামিতি গ্রহণ করা হয়, বা ফিরে আছে হতে publicএবং অ জেনেরিক। এটি অ-জেনেরিক হতে হবে কারণ জেনেরিক প্রকারগুলি স্পষ্টতই অ্যাক্সেস করে System.__Canonযা জেনেরিক প্রকারের জন্য হুডের অধীনে .NET দ্বারা ব্যবহৃত অভ্যন্তরীণ প্রকার এবং এটি " publicটাইপ বিধি হতে হবে" লঙ্ঘন করে ।

এই ধরণের জন্য, আপনি স্পষ্টতই ধীর ব্যবহার করতে পারেন Compile। আমি তাদের নিম্নলিখিত উপায়ে সনাক্ত করি:

private static bool IsPublicType(Type t)
{

  if ((!t.IsPublic && !t.IsNestedPublic) || t.IsGenericType)
  {
    return false;
  }

  int lastIndex = t.FullName.LastIndexOf('+');

  if (lastIndex > 0)
  {
    var containgTypeName = t.FullName.Substring(0, lastIndex);

    var containingType = Type.GetType(containgTypeName + "," + t.Assembly);

    if (containingType != null)
    {
      return containingType.IsPublic;
    }

    return false;
  }
  else
  {
    return t.IsPublic;
  }
}

তবে আমি যেমন বলেছিলাম, এটি আদর্শ নয় এবং আমি এখনও জানতে চাই কেন একটি গতিশীল সমাবেশে কোনও পদ্ধতি সংকলন করা অনেক সময় দ্রুততর মানের ক্রম হয়। এবং আমি মাঝে মাঝে বলি কারণ আমি এমন কেসগুলিও দেখেছি যেখানে একটি Expressionসংকলিত Compileএকটি সাধারণ পদ্ধতির মতোই দ্রুত is তার জন্য আমার প্রশ্ন দেখুন।

অথবা যদি কেউ publicগতিশীল সমাবেশের সাথে " অ- ধরণের" বাধা ছাড়ার কোনও উপায় জানেন তবে এটিও স্বাগত।


4

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

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

আপনি HandMadeLambdaExpression()পদ্ধতিতে আপনার তৃতীয় প্রশ্নের আমার উত্তর খুঁজে পাবেন । এক্সটেনশন পদ্ধতির কারণে তৈরি করা সবচেয়ে সহজ অভিব্যক্তি নয়, তবেযোগ্য।

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

using System.Diagnostics;
using System.Linq.Expressions;

namespace ExpressionBench
{
    class Program
    {
        static void Main(string[] args)
        {
            var values = Enumerable.Range(0, 5000);
            var lambda = GetLambda();
            var lambdaExpression = GetLambdaExpression().Compile();
            var handMadeLambdaExpression = GetHandMadeLambdaExpression().Compile();
            var composed = GetComposed();
            var composedExpression = GetComposedExpression().Compile();
            var handMadeComposedExpression = GetHandMadeComposedExpression().Compile();

            DoTest("Lambda", values, lambda);
            DoTest("Lambda Expression", values, lambdaExpression);
            DoTest("Hand Made Lambda Expression", values, handMadeLambdaExpression);
            Console.WriteLine();
            DoTest("Composed", values, composed);
            DoTest("Composed Expression", values, composedExpression);
            DoTest("Hand Made Composed Expression", values, handMadeComposedExpression);
        }

        static void DoTest<TInput, TOutput>(string name, TInput sequence, Func<TInput, TOutput> operation, int count = 1000000)
        {
            for (int _ = 0; _ < 1000; _++)
                operation(sequence);
            var sw = Stopwatch.StartNew();
            for (int _ = 0; _ < count; _++)
                operation(sequence);
            sw.Stop();
            Console.WriteLine("{0}:", name);
            Console.WriteLine("  Elapsed: {0,10} {1,10} (ms)", sw.ElapsedTicks, sw.ElapsedMilliseconds);
            Console.WriteLine("  Average: {0,10} {1,10} (ms)", decimal.Divide(sw.ElapsedTicks, count), decimal.Divide(sw.ElapsedMilliseconds, count));
        }

        static Func<IEnumerable<int>, IList<int>> GetLambda()
        {
            return v => v.Where(i => i % 2 == 0).Where(i => i > 5).ToList();
        }

        static Expression<Func<IEnumerable<int>, IList<int>>> GetLambdaExpression()
        {
            return v => v.Where(i => i % 2 == 0).Where(i => i > 5).ToList();
        }

        static Expression<Func<IEnumerable<int>, IList<int>>> GetHandMadeLambdaExpression()
        {
            var enumerableMethods = typeof(Enumerable).GetMethods();
            var whereMethod = enumerableMethods
                .Where(m => m.Name == "Where")
                .Select(m => m.MakeGenericMethod(typeof(int)))
                .Where(m => m.GetParameters()[1].ParameterType == typeof(Func<int, bool>))
                .Single();
            var toListMethod = enumerableMethods
                .Where(m => m.Name == "ToList")
                .Select(m => m.MakeGenericMethod(typeof(int)))
                .Single();

            // helpers to create the static method call expressions
            Func<Expression, ParameterExpression, Func<ParameterExpression, Expression>, Expression> WhereExpression =
                (instance, param, body) => Expression.Call(whereMethod, instance, Expression.Lambda(body(param), param));
            Func<Expression, Expression> ToListExpression =
                instance => Expression.Call(toListMethod, instance);

            //return v => v.Where(i => i % 2 == 0).Where(i => i > 5).ToList();
            var exprParam = Expression.Parameter(typeof(IEnumerable<int>), "v");
            var expr0 = WhereExpression(exprParam,
                Expression.Parameter(typeof(int), "i"),
                i => Expression.Equal(Expression.Modulo(i, Expression.Constant(2)), Expression.Constant(0)));
            var expr1 = WhereExpression(expr0,
                Expression.Parameter(typeof(int), "i"),
                i => Expression.GreaterThan(i, Expression.Constant(5)));
            var exprBody = ToListExpression(expr1);
            return Expression.Lambda<Func<IEnumerable<int>, IList<int>>>(exprBody, exprParam);
        }

        static Func<IEnumerable<int>, IList<int>> GetComposed()
        {
            Func<IEnumerable<int>, IEnumerable<int>> composed0 =
                v => v.Where(i => i % 2 == 0);
            Func<IEnumerable<int>, IEnumerable<int>> composed1 =
                v => v.Where(i => i > 5);
            Func<IEnumerable<int>, IList<int>> composed2 =
                v => v.ToList();
            return v => composed2(composed1(composed0(v)));
        }

        static Expression<Func<IEnumerable<int>, IList<int>>> GetComposedExpression()
        {
            Expression<Func<IEnumerable<int>, IEnumerable<int>>> composed0 =
                v => v.Where(i => i % 2 == 0);
            Expression<Func<IEnumerable<int>, IEnumerable<int>>> composed1 =
                v => v.Where(i => i > 5);
            Expression<Func<IEnumerable<int>, IList<int>>> composed2 =
                v => v.ToList();
            var exprParam = Expression.Parameter(typeof(IEnumerable<int>), "v");
            var exprBody = Expression.Invoke(composed2, Expression.Invoke(composed1, Expression.Invoke(composed0, exprParam)));
            return Expression.Lambda<Func<IEnumerable<int>, IList<int>>>(exprBody, exprParam);
        }

        static Expression<Func<IEnumerable<int>, IList<int>>> GetHandMadeComposedExpression()
        {
            var enumerableMethods = typeof(Enumerable).GetMethods();
            var whereMethod = enumerableMethods
                .Where(m => m.Name == "Where")
                .Select(m => m.MakeGenericMethod(typeof(int)))
                .Where(m => m.GetParameters()[1].ParameterType == typeof(Func<int, bool>))
                .Single();
            var toListMethod = enumerableMethods
                .Where(m => m.Name == "ToList")
                .Select(m => m.MakeGenericMethod(typeof(int)))
                .Single();

            Func<ParameterExpression, Func<ParameterExpression, Expression>, Expression> LambdaExpression =
                (param, body) => Expression.Lambda(body(param), param);
            Func<Expression, ParameterExpression, Func<ParameterExpression, Expression>, Expression> WhereExpression =
                (instance, param, body) => Expression.Call(whereMethod, instance, Expression.Lambda(body(param), param));
            Func<Expression, Expression> ToListExpression =
                instance => Expression.Call(toListMethod, instance);

            var composed0 = LambdaExpression(Expression.Parameter(typeof(IEnumerable<int>), "v"),
                v => WhereExpression(
                    v,
                    Expression.Parameter(typeof(int), "i"),
                    i => Expression.Equal(Expression.Modulo(i, Expression.Constant(2)), Expression.Constant(0))));
            var composed1 = LambdaExpression(Expression.Parameter(typeof(IEnumerable<int>), "v"),
                v => WhereExpression(
                    v,
                    Expression.Parameter(typeof(int), "i"),
                    i => Expression.GreaterThan(i, Expression.Constant(5))));
            var composed2 = LambdaExpression(Expression.Parameter(typeof(IEnumerable<int>), "v"),
                v => ToListExpression(v));

            var exprParam = Expression.Parameter(typeof(IEnumerable<int>), "v");
            var exprBody = Expression.Invoke(composed2, Expression.Invoke(composed1, Expression.Invoke(composed0, exprParam)));
            return Expression.Lambda<Func<IEnumerable<int>, IList<int>>>(exprBody, exprParam);
        }
    }
}

এবং আমার মেশিনে ফলাফল:

লাম্বদা:
  অতিবাহিত: 340971948 123230 (এমএস)
  গড়: 340.971948 0.12323 (এমএস)
লাম্বদা এক্সপ্রেশন:
  অতিবাহিত: 357077202 129051 (এমএস)
  গড়: 357.077202 0.129051 (এমএস)
হাতে তৈরি লাম্বদা এক্সপ্রেশন:
  অতিবাহিত: 345029281 124696 (এমএস)
  গড়: 345.029281 0.124696 (এমএস)

রচনা:
  অতিবাহিত: 340409238 123027 (এমএস)
  গড়: 340.409238 0.123027 (এমএস)
রচনা প্রকাশ:
  অতিবাহিত: 350800599 126782 (এমএস)
  গড়: 350.800599 0.126782 (এমএস)
হাতে তৈরি কমপোজড এক্সপ্রেশন:
  অতিবাহিত: 352811359 127509 (এমএস)
  গড়: 352.811359 0.127509 (এমএস)

3

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

দ্বিতীয়ত, একাধিক ল্যাম্বডা এক্সপ্রেশন মানে একাধিক বেনামে পদ্ধতি, এবং তাদের প্রত্যেককে কল করা একটি সরল পদ্ধতি মূল্যায়নের জন্য কিছুটা অতিরিক্ত সময় নেয়। উদাহরণস্বরূপ, কল করা

Console.WriteLine(x);

এবং

Action x => Console.WriteLine(x);
x(); // this means two different calls..

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

সুতরাং আপনার সম্মিলিত লাম্বদা অবশ্যই একক ল্যাম্বডা এক্সপ্রেশনের তুলনায় সামান্য ধীর পারফরম্যান্স করবে।

এবং এটি ভিতরে যা কার্যকর করছে তার থেকে এটি স্বাধীন, কারণ আপনি এখনও সঠিক যুক্তির মূল্যায়ন করছেন তবে সংকলক সম্পাদন করার জন্য আপনি অতিরিক্ত পদক্ষেপ যুক্ত করছেন।

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


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

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

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