কার্যকরী প্রোগ্রামিং - অপরিবর্তনীয়তা ব্যয়বহুল? [বন্ধ]


98

প্রশ্নটি দুটি ভাগে। প্রথমটি ধারণামূলক। পরের স্ক্যালায় একই প্রশ্নটিকে আরও দৃ concrete়তার সাথে দেখায়।

  1. কোন প্রোগ্রামিং ভাষায় কেবলমাত্র অপরিবর্তনীয় ডেটা স্ট্রাকচার ব্যবহারের ফলে কিছু নির্দিষ্ট অ্যালগরিদম / যুক্তি সহজাতভাবে বাস্তবায়নে কম্পিউটারের ব্যয় আরও বেশি ব্যয় হয়? এটি এ সত্যটির প্রতি দৃষ্টি আকর্ষণ করে যে অপরিবর্তনীয়তা নিখুঁত কার্যকরী ভাষার মূল শিক্ষিকা। এটি প্রভাবিত অন্যান্য কারণ আছে?
  2. এর আরও দৃ concrete় উদাহরণ গ্রহণ করা যাক। কুইকসোর্ট সাধারণত মেমরির ইন-মেমরি স্ট্রাকচারে পরিবর্তনীয় ক্রিয়াকলাপগুলি শেখানো এবং প্রয়োগ করা হয়। কীভাবে কেউ মিউটেবল সংস্করণে তুলনীয় কম্পিউটিশনাল এবং স্টোরেজ ওভারহেড সহ একটি বিশুদ্ধ কার্যকরী উপায়ে এই জাতীয় জিনিস বাস্তবায়ন করে। বিশেষত স্কালায়। আমি নীচে কিছু অপরিশোধিত মানদণ্ড অন্তর্ভুক্ত করেছি।

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

আমি একটি অত্যাবশ্যক প্রোগ্রামিং ব্যাকগ্রাউন্ড (সি ++, জাভা) থেকে এসেছি। আমি ক্রিয়ামূলক প্রোগ্রামিং, বিশেষত স্কালার অন্বেষণ করেছি।

খাঁটি কার্যকরী প্রোগ্রামিংয়ের প্রাথমিক নীতিগুলির কয়েকটি:

  1. কাজগুলি প্রথম শ্রেণির নাগরিক।
  2. ফাংশনগুলির পার্শ্ব প্রতিক্রিয়া নেই এবং তাই অবজেক্ট / ডেটা স্ট্রাকচার অপরিবর্তনীয়

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

একটি নির্দিষ্ট কেস হিসাবে, আমি এই টিউটোরিয়াল 6-র এই কোড স্নিপেট থেকে কিছুটা অবাক হয়েছিলাম । এটিতে কুইকসোর্টের একটি জাভা সংস্করণ রয়েছে যার পরে এটির ঝরঝরে ঝরঝরে বাস্তবায়ন রয়েছে।

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

জাভা সংস্করণ

public class QuickSortJ {

    public static void sort(int[] xs) {
      sort(xs, 0, xs.length -1 );
    }

    static void sort(int[] xs, int l, int r) {
      if (r >= l) return;
      int pivot = xs[l];
      int a = l; int b = r;
      while (a <= b){
        while (xs[a] <= pivot) a++;
        while (xs[b] > pivot) b--;
        if (a < b) swap(xs, a, b);
      }
      sort(xs, l, b);
      sort(xs, a, r);
    }

    static void swap(int[] arr, int i, int j) {
      int t = arr[i]; arr[i] = arr[j]; arr[j] = t;
    }
}

স্কালা সংস্করণ

object QuickSortS {

  def sort(xs: Array[Int]): Array[Int] =
    if (xs.length <= 1) xs
    else {
      val pivot = xs(xs.length / 2)
      Array.concat(
        sort(xs filter (pivot >)),
        xs filter (pivot ==),
        sort(xs filter (pivot <)))
    }
}

বাস্তবায়ন তুলনা করতে স্কেল কোড

import java.util.Date
import scala.testing.Benchmark

class BenchSort(sortfn: (Array[Int]) => Unit, name:String) extends Benchmark {

  val ints = new Array[Int](100000);

  override def prefix = name
  override def setUp = {
    val ran = new java.util.Random(5);
    for (i <- 0 to ints.length - 1)
      ints(i) = ran.nextInt();
  }
  override def run = sortfn(ints)
}

val benchImmut = new BenchSort( QuickSortS.sort , "Immutable/Functional/Scala" )
val benchMut   = new BenchSort( QuickSortJ.sort , "Mutable/Imperative/Java   " )

benchImmut.main( Array("5"))
benchMut.main( Array("5"))

ফলাফল

টানা পাঁচ রানের জন্য মিলিসেকেন্ডে সময়

Immutable/Functional/Scala    467    178    184    187    183
Mutable/Imperative/Java        51     14     12     12     12

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

4
একটি দুর্দান্ত, সম্পর্কিত ব্লগ নিবন্ধটি এখানে রয়েছে: ব্লগস.সুন.com / জ্রোস / এন্ট্রি / স্পেসিওটি_জেক্টস_ইন_এইচএম তাকে উত্সাহিত করে, কারণ এটি জাভা এবং ফাংশনাল ভিএম ভাষার পক্ষে ব্যাপক উপকার করবে
andersoj

4
এই এসও থ্রেডে কার্যকরী প্রোগ্রামিংয়ের দক্ষতা সম্পর্কে প্রচুর বিস্তারিত আলোচনা রয়েছে। stackoverflow.com/questions/1990464/… । আমি যা জানতে চেয়েছিলাম তার একটি দুর্দান্ত চুক্তির উত্তর দেয়।
স্মার্টনট 700

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

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

উত্তর:


106

যেহেতু এখানে প্রায় কয়েকটি ভুল ধারণা রয়েছে, তাই আমি কয়েকটি বিষয় পরিষ্কার করতে চাই।

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

  • অ্যারেগুলিতে চালিত কুইকোর্টের ক্রিয়ামূলক বৈকল্পিক প্রয়োগ করা উদ্দেশ্যটিকে পরাস্ত করে। অ্যারে কখনও স্থাবর হয় না।

  • কুইকোর্টের "যথাযথ" কার্যকরী বাস্তবায়ন অপরিবর্তনীয় তালিকা ব্যবহার করে। এটি অবশ্যই স্থানে নেই তবে প্রক্রিয়াভুক্ত সংস্করণ হিসাবে এটি একই নিকৃষ্টতম অ্যাসিম্পটোটিক রানটাইম ( ( এন ^ 2)) এবং স্থান জটিলতা ( ( এন )) পেয়েছে।

    গড়ে, এটির চলমান সময়টি এখনও ইন-প্লেস ভেরিয়েন্টের সাথে সমান ( ( এন লগ এন ))। এর স্পেস জটিলতা অবশ্য এখনও ( এন )।


আছে দুই সুস্পষ্ট অসুবিধেও একটি কার্মিক quicksort প্রয়োগের। নিম্নলিখিতটিতে, আসুন Haskell (আমি স্কালাকে চিনি না ...) হাস্কেলের ভূমিকা থেকে এই রেফারেন্স বাস্তবায়ন বিবেচনা করি :

qsort []     = []
qsort (x:xs) = qsort lesser ++ [x] ++ qsort greater
    where lesser  = (filter (< x) xs)
          greater = (filter (>= x) xs)
  1. প্রথম অসুবিধাটি হ'ল পিভট এলিমেন্টের পছন্দ , যা খুব জটিল। আধুনিক কুইকোর্টের বাস্তবায়নের শক্তি মূলত একটি স্মার্ট পছন্দের উপর নির্ভর করে ( বেন্টলি এট আল দ্বারা "ইঞ্জিনিয়ারিং একটি ধরণের ফাংশন" তুলনা করুন )। উপরের অ্যালগরিদম সেই ক্ষেত্রে দরিদ্র যা গড় পারফরম্যান্সকে যথেষ্ট হ্রাস করে।

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

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


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

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

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


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

এবং অপরিবর্তনীয়তা এমনকি ব্যয়বহুল অনুলিপি বা ক্রস-থ্রেড সিঙ্ক্রোনাইজেশনের প্রয়োজনীয়তা অপসারণ করে কর্মক্ষমতা ব্যয় হ্রাস করতে পারে ।

সুতরাং, মূল প্রশ্নের উত্তর দিতে, " অপরিবর্তনীয়তা ব্যয়বহুল কি? ”- কুইকোর্টের বিশেষ ক্ষেত্রে, একটি ব্যয় রয়েছে যা বাস্তবে অপরিবর্তনীয়তার ফলস্বরূপ। তবে সাধারণভাবে, না


10
+1 - দুর্দান্ত উত্তর! যদিও আমি ব্যক্তিগতভাবে দিয়ে শেষ হবে কখনও কখনও বদলে কোন । তবুও, এটি কেবল ব্যক্তিত্ব - আপনি বিষয়গুলি খুব ভালভাবে ব্যাখ্যা করেছেন।
রেক্স কের

6
আপনার যুক্ত করা উচিত যে অপরিবর্তনীয় মানগুলি ব্যবহার করে একটি যথাযথ বাস্তবায়ন অপরিহার্য সংস্করণগুলির বিপরীতে তাত্ক্ষণিকভাবে সমান্তরাল। আধুনিক প্রযুক্তিগত প্রসঙ্গে এটি আরও বেশি গুরুত্বপূর্ণ হয়ে ওঠে।
রাফেল

qsort lesser ++ (x : qsort greater)সাহায্য কত ব্যবহার করবে ?
সলোমন উকো

42

ফাংশনাল প্রোগ্রামিংয়ের মানদণ্ড হিসাবে এর সাথে বেশ কিছু জিনিস ভুল রয়েছে। হাইলাইটগুলি অন্তর্ভুক্ত:

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

সুতরাং, এই তুলনাটি একটি দুর্দান্ত উদাহরণ যা উচ্চ-পারফরম্যান্স কোড লিখতে আপনাকে অবশ্যই আপনার ভাষা (এবং অ্যালগরিদম) বিস্তারিত বুঝতে হবে। তবে এটি এফপি বনাম নন-এফপির খুব ভাল তুলনা নয়। যদি আপনি এটি চান, কম্পিউটার ভাষা বেঞ্চমার্ক গেমটিতে হাস্কেল বনাম সি ++ দেখুন । সেখানে নিয়ে যাওয়া বার্তাটি হ'ল পেনাল্টিটি সাধারণত 2 বা 3 বা ততোধিক ফ্যাক্টরের চেয়ে বেশি নয়, তবে এটি সত্যই নির্ভর করে। (কোন প্রতিশ্রুতি নেই যে হাসকল লোকেরা সম্ভবত দ্রুততম অ্যালগরিদমগুলি রচনা করেছে, তবে তাদের মধ্যে কমপক্ষে কিছু সম্ভবত চেষ্টা করেছে! তারপরে আবার কিছু হাস্কেল সি লাইব্রেরি কল করে ....)

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

object QSortExample {
  // Imperative mutable quicksort
  def swap(xs: Array[String])(a: Int, b: Int) {
    val t = xs(a); xs(a) = xs(b); xs(b) = t
  }
  def muQSort(xs: Array[String])(l: Int = 0, r: Int = xs.length-1) {
    val pivot = xs((l+r)/2)
    var a = l
    var b = r
    while (a <= b) {
      while (xs(a) < pivot) a += 1
      while (xs(b) > pivot) b -= 1
      if (a <= b) {
        swap(xs)(a,b)
        a += 1
        b -= 1
      }
    }
    if (l<b) muQSort(xs)(l, b)
    if (b<r) muQSort(xs)(a, r)
  }

  // Functional quicksort
  def fpSort(xs: Array[String]): Array[String] = {
    if (xs.length <= 1) xs
    else {
      val pivot = xs(xs.length/2)
      val (small,big) = xs.partition(_ < pivot)
      if (small.length == 0) {
        val (bigger,same) = big.partition(_ > pivot)
        same ++ fpSort(bigger)
      }
      else fpSort(small) ++ fpSort(big)
    }
  }

  // Utility function to repeat something n times
  def repeat[A](n: Int, f: => A): A = {
    if (n <= 1) f else { f; repeat(n-1,f) }
  }

  // This runs the benchmark
  def bench(n: Int, xs: Array[String], silent: Boolean = false) {
    // Utility to report how long something took
    def ptime[A](f: => A) = {
      val t0 = System.nanoTime
      val ans = f
      if (!silent) printf("elapsed: %.3f sec\n",(System.nanoTime-t0)*1e-9)
      ans
    }

    if (!silent) print("Scala builtin ")
    ptime { repeat(n, {
      val ys = xs.clone
      ys.sorted
    }) }
    if (!silent) print("Mutable ")
    ptime { repeat(n, {
      val ys = xs.clone
      muQSort(ys)()
      ys
    }) }
    if (!silent) print("Immutable ")
    ptime { repeat(n, {
      fpSort(xs)
    }) }
  }

  def main(args: Array[String]) {
    val letters = (1 to 500000).map(_ => scala.util.Random.nextPrintableChar)
    val unsorted = letters.grouped(5).map(_.mkString).toList.toArray

    repeat(3,bench(1,unsorted,silent=true))  // Warmup
    repeat(3,bench(10,unsorted))     // Actual benchmark
  }
}

ফাংশনাল কুইকসোর্টে পরিবর্তনটি নোট করুন যাতে এটি যদি সম্ভব হয় কেবল তখনই ডেটা দিয়ে যায় এবং বিল্ট-ইন বাছাইয়ের সাথে তুলনা করে। আমরা এটি চালানোর সময় আমরা এরকম কিছু পাই:

Scala builtin elapsed: 0.349 sec
Mutable elapsed: 0.445 sec
Immutable elapsed: 1.373 sec
Scala builtin elapsed: 0.343 sec
Mutable elapsed: 0.441 sec
Immutable elapsed: 1.374 sec
Scala builtin elapsed: 0.343 sec
Mutable elapsed: 0.442 sec
Immutable elapsed: 1.383 sec

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


শুধু বক্সিং / আনবক্সিং সম্পর্কিত। যদি কিছু হয় তবে ডানদিকে জাভা দিকের এই জরিমানা হওয়া উচিত? স্ক্যান (বনাম পূর্ণসংখ্যার) এর জন্য পছন্দসই সংখ্যার প্রকারটি নয় nt সুতরাং, স্কালার দিক থেকে সুখী কোনও বক্সিং নেই। জাভা সাইডে বক্সিং করা কেবলমাত্র একটি সমস্যা কারণ অটোবক্সিং ফর্ম স্কেল ইন জাভা.এল.আং.ইন্টিজার / ইনট। এই লিঙ্কটি এখানে এই বিষয়ে বিস্তারিতভাবে কথা বলেছে Ansorg-it.com/en/scalanews-001.html
স্মার্টনট 700

হ্যাঁ, আমি এখানে শয়তানদের উকিল খেলছি। মিউটেবিলিটি কুইকোর্টস ডিজাইনের একটি অন্তর্গত অংশ। সমস্যাটির খাঁটি কার্যকরী পদ্ধতির বিষয়ে কেন আমি খুব কৌতূহল বোধ করি ts দীর্ঘশ্বাস ফেলুন, আমি দশ মিনিটে এই বিবৃতিটি থ্রেডে বলেছি :-)। আমি যখন জেগে উঠব এবং ফিরে আসব তখন আপনার পোস্টের বাকী অংশটি দেখবে। ধন্যবাদ
স্মার্টনট 700

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

আপনি যে শীর্ষস্থানীয় ত্রুটিটি বলেছেন তা কেবল একটি অনুমান :-)
স্মার্টনাট 700

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

10

আপনি যেহেতু ব্যবহার করছেন তাই স্কেল সংস্করণটি আসলে টেল রিকার্সিভ বলে মনে হয় না Array.concat

এছাড়াও, শুধুমাত্র এটি আইডেম্যাটিক স্কাল কোড হিসাবে, এর অর্থ এই নয় যে এটি করা ভাল উপায় is

এটি করার সর্বোত্তম উপায় হ'ল স্কালার অন্তর্নির্মিত বাছাই করা ফাংশনগুলির একটি ব্যবহার করা। এইভাবে আপনি অযোগ্যতা গ্যারান্টি পাবেন এবং জেনে নিন আপনার একটি দ্রুত অ্যালগরিদম রয়েছে।

স্ট্যাক ওভারফ্লো প্রশ্ন দেখুন আমি কীভাবে স্কালায় একটি অ্যারে বাছাই করব? একটি উদাহরণ জন্য।


4
এছাড়াও, আমি মনে করি না যে একটি লেজ পুনরাবৃত্তির দ্রুত সাজানোর সম্ভাবনা রয়েছে, কারণ আপনাকে দুটি পুনরাবৃত্ত কল করতে হবে
অ্যালেক্স লো

4
এটি সম্ভব, আপনার কেবলমাত্র স্ট্যাক-ফ্রেমগুলি গাদাতে তুলতে আপনাকে কেবল ধারাবাহিকতা বন্ধ করতে হবে।
ব্রায়ান

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

@ স্মার্টনাট 700: আপনি স্কালার কোন সংস্করণ ব্যবহার করছেন? স্কেলা ২.৮ এ আপনি এমনটি করতে পারেন array.sortedযা কোনও নতুন সাজানো অ্যারে দেয়, আসলটি রূপান্তরিত করে না।
অনুপস্থিতি

@ অ্যালেক্সলো - একটি পুচ্ছ পুনরাবৃত্তির দ্রুত সাজানোর সম্ভাবনা রয়েছে। এর মতো কিছু:TAIL-RECURSIVE-QUICKSORT(Array A, int lo, int hi): while p < r: q = PARTITION(A, lo, hi); TAIL-RECURSIVE-QUICKSORT(A, lo, q - 1); p = q + 1;
জেকওয়ে

8

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

এটিকে সহজভাবে বলতে গেলে, খাঁটি কার্যকরী ভাষা ব্যবহার করার সময় আপনি কোঁকড়ে উঠবেন না।

এর অন্য একটি কোণ থেকে বিবেচনা করা যাক। আসুন এই দুটি ফাংশন বিবেচনা করুন:

// Version using mutable data structures
def tailFrom[T : ClassManifest](arr: Array[T], p: T => Boolean): Array[T] = {
  def posIndex(i: Int): Int = {
    if (i < arr.length) {
      if (p(arr(i)))
        i
      else
        posIndex(i + 1)
    } else {
      -1
    }
  }

  var index = posIndex(0)

  if (index < 0) Array.empty
  else {
    var result = new Array[T](arr.length - index)
    Array.copy(arr, index, result, 0, arr.length - index)
    result
  }
}

// Immutable data structure:

def tailFrom[T](list: List[T], p: T => Boolean): List[T] = {
  def recurse(sublist: List[T]): List[T] = {
    if (sublist.isEmpty) sublist
    else if (p(sublist.head)) sublist
    else recurse(sublist.tail)
  }
  recurse(list)
}

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

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

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


7

একটি অ্যারের বাছাই করা যেমন মহাবিশ্বের সবচেয়ে আবশ্যক কাজ। অবাক হওয়ার মতো বিষয় নয় যে অনেক মার্জিত 'অপরিবর্তনীয়' কৌশল / বাস্তবায়ন একটি 'অ্যারে বাছাই করা' মাইক্রোব্যাঙ্কমার্কের উপর খারাপভাবে ব্যর্থ হয়। যদিও এটি বোঝায় না যে অপরিবর্তনশীলতা "সাধারণভাবে" ব্যয়বহুল। অনেকগুলি কাজ রয়েছে যেখানে অপরিবর্তনীয় বাস্তবায়নগুলি পরিবর্তনীয়গুলির সাথে তুলনামূলকভাবে সঞ্চালন করবে, তবে প্রায়শই অ্যারে বাছাই করা সেগুলির মধ্যে একটি নয়।


7

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


আপনি স্কালায় একটি বাস্তবায়ন প্রদান করতে যথেষ্ট সদয় হতে পারেন?
স্মার্টনাট 700

4
Powells.com/biblio/17-0521631246-0 (ক্রিস ওকাসাকির খাঁটি ফাংশনাল ডেটা স্ট্রাকচার) - কেবল এই বইটি দেখুন। কার্যকর অ্যালগরিদম এবং ডেটা স্ট্রাকচার বাস্তবায়ন করার সময়, কার্যকরী প্রোগ্রামিং সুবিধাগুলি উপকারের বিষয়ে বলার একটি দৃ strong় কাহিনী রয়েছে।
ভাসিল রেমেনিয়ুক

4
কোড.google.com/p/pfds স্ক্যানায় কিছু ডেটা স্ট্রাকচার প্রয়োগ করা হয়েছে দেবাশীষ ঘোষ
ভাসিল রেমেনিয়ুক

আপনি দয়া করে ব্যাখ্যা করতে পারেন যে আপনি কেন মনে করেন যে স্কালা অপরিহার্য নয়? list.filter (foo).sort (bar).take (10)- এর চেয়ে বেশি জরুরি কী হতে পারে?
ব্যবহারকারী অজানা

7

স্কালায় অপরিবর্তনশীলতার ব্যয়

এখানে একটি সংস্করণ যা জাভা সংস্করণের চেয়ে প্রায় দ্রুত। ;)

object QuickSortS {
  def sort(xs: Array[Int]): Array[Int] = {
    val res = new Array[Int](xs.size)
    xs.copyToArray(res)
    (new QuickSortJ).sort(res)
    res
  }
}

এই সংস্করণটি অ্যারের একটি অনুলিপি তৈরি করে, জাভা সংস্করণটি ব্যবহার করে এটি সাজিয়ে তোলে এবং অনুলিপিটি প্রদান করে। স্কালা আপনাকে অভ্যন্তরীণভাবে অপরিবর্তনীয় কাঠামো ব্যবহার করতে বাধ্য করে না।

সুতরাং স্কেলার সুবিধা হ'ল আপনি যেভাবে ফিট হবে তা পরিবর্তন এবং অপরিবর্তনীয়তা লাভ করতে পারেন। অসুবিধাটি হ'ল আপনি যদি এটি ভুল করেন তবে আপনি সত্যিকারের অপরিবর্তনীয়তার সুবিধা পাবেন না।


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

7

কুইকসোর্টটি ইন-প্লেসে কাজ করার সময় দ্রুততর হিসাবে পরিচিত, তাই এটি খুব কমই তুলনামূলকভাবে উপযুক্ত!

বলেছে ... অ্যারে.কনক্যাট? যদি অন্য কিছু না হয়, আপনি যখন দেখিয়েছেন যে কোনও সংগ্রহের প্রবণতা প্রয়োজনীয় প্রোগ্রামিংয়ের জন্য অনুকূলিত করা হয়েছে তখন কীভাবে বিশেষভাবে ধীর হয় যখন আপনি চেষ্টা করে এটি কার্যকরী অ্যালগরিদমে ব্যবহার করেন; প্রায় অন্য কোনও পছন্দ দ্রুত হবে!


আরেকটি খুব গুরুত্বপূর্ণ পয়েন্ট বিবেচনা করা, সম্ভবত সবচেয়ে গুরুত্বপূর্ণ বিষয় দুটি তুলনা পন্থা হল: "কত ভাল একাধিক নোড / কোর কাছে এই স্কেল আছে"

সম্ভাবনাগুলি হ'ল, যদি আপনি একটি অপরিবর্তনীয় কুইকোর্টের সন্ধান করেন তবে আপনি এটি করছেন কারণ আপনি আসলে একটি সমান্তরাল কোকোসোর্ট চান। উইকিপিডিয়ায় এই বিষয়ে কিছু উদ্ধৃতি রয়েছে: http://en.wikedia.org/wiki/Quicksort# সমান্তরালীকরণ

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

এই মুহুর্তে, আমার সিস্টেমে জিপিইউতে আমার কাছে 128 টি কোর উপলব্ধ রয়েছে যদি আমি এটিতে কেবল স্কাল কোডটি চালাতে পারি, এবং এটি বর্তমান প্রজন্মের দু'বছর পিছনে একটি সাধারণ ডেস্কটপ সিস্টেমে রয়েছে।

আমি ভাবছি যে একক থ্রেডযুক্ত অপরিহার্য পদ্ধতির বিরুদ্ধে এটি কীভাবে দাঁড়াবে ...

সম্ভবত আরও গুরুত্বপূর্ণ প্রশ্নটি হ'ল:

"প্রদত্ত যে পৃথক কোরগুলি আরও দ্রুততর হয় না, এবং সমলয়করণ / লক করা সমান্তরালতার জন্য একটি সত্যিকারের চ্যালেঞ্জ উপস্থাপন করে, তা কি মিউটিবিলিটি ব্যয়বহুল?"


সেখানে কোন যুক্তি নেই। কুইকসোর্টটি একটি মেমরি সাজানোর সংজ্ঞা অনুসারে হয়। আমি নিশ্চিত যে বেশিরভাগ মানুষ কলেজ থেকে এটি মনে রাখে। তবে, আপনি কীভাবে খাঁটি কার্যকরী উপায়ে চুষতে থাকেন। অর্থাত্ পার্শ্ব প্রতিক্রিয়া ছাড়াই।
স্মার্টনট 700 7

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

তালিকা সংস্করণটি অর্ধেক সময় কেটে দেয়। তবুও, জাভা সংস্করণের গতির কাছের কোনও জায়গা নেই।
স্মার্টনাট 700

আপনি দয়া করে ব্যাখ্যা করতে পারেন যে আপনি কেন মনে করেন যে স্কালা অপরিহার্য নয়? list.filter (foo).sort (bar).take (10)- এর চেয়ে বেশি জরুরি কী হতে পারে? ধন্যবাদ
ব্যবহারকারী অজানা

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

2

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


আপনি দয়া করে ব্যাখ্যা করতে পারেন যে আপনি কেন মনে করেন যে স্কালা অপরিহার্য নয়? list.filter (foo).sort (bar).take (10)- এর চেয়ে বেশি জরুরি কী হতে পারে? ধন্যবাদ
ব্যবহারকারী অজানা

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