স্কালার জন্য কোন স্বয়ংক্রিয় সংস্থান ব্যবস্থাপনার বিকল্প বিদ্যমান?


102

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

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


যদি এই সম্প্রদায় উইকি না হয় তবে এই প্রশ্নটি আরও উত্তর তৈরি করতে পারে? কমিউনিটির উইকি পুরষ্কারের খ্যাতিতে উত্তরগুলি যদি ভোট দেওয়া হয় তা নিশ্চিত করুন ...
huynhjl

2
অনন্য রেফারেন্সগুলি এআরএম-এ সুরক্ষার আরও একটি স্তর জুড়তে পারে তা নিশ্চিত করতে যে সংস্থানগুলি () বলা হওয়ার আগে ম্যানেজারের কাছে উত্সগুলির রেফারেন্সগুলি ফিরে আসে। सूत्र.gmane.org/gmane.comp.lang.scala/19160/fochet=19168
retronym

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

1
যেহেতু আমার একাধিক java.lang.AutoCloseable দৃষ্টান্তগুলি বাসাতে সক্ষম হতে হবে, যার প্রত্যেকটি সাফল্যের সাথে ইনস্ট্যান্ট করার পূর্বের উপর নির্ভর করে, অবশেষে আমি এমন একটি প্যাটার্নটিতে আঘাত করি যা আমার পক্ষে খুব কার্যকর। : আমি অনুরূপ Stackoverflow প্রশ্ন উত্তর হিসেবে এটা লিখেছে stackoverflow.com/a/34277491/501113
chaotic3quilibrium

উত্তর:


10

আপাতত স্কেলা ২.১13 শেষ পর্যন্ত সমর্থন করেছে: :) try with resourcesব্যবহার করে উদাহরণস্বরূপ:

val lines: Try[Seq[String]] =
  Using(new BufferedReader(new FileReader("file.txt"))) { reader =>
    Iterator.unfold(())(_ => Option(reader.readLine()).map(_ -> ())).toList
  }

বা Using.resourceএড়ানো ব্যবহারTry

val lines: Seq[String] =
  Using.resource(new BufferedReader(new FileReader("file.txt"))) { reader =>
    Iterator.unfold(())(_ => Option(reader.readLine()).map(_ -> ())).toList
  }

আপনি ডক ব্যবহার করে আরও উদাহরণ পেতে পারেন ।

স্বয়ংক্রিয় সংস্থান পরিচালনা করার জন্য একটি ইউটিলিটি। এটি সংস্থানগুলি ব্যবহার করে একটি ক্রিয়াকলাপ সম্পাদন করতে ব্যবহার করা যেতে পারে, তারপরে এটি সংস্থানগুলি বিপরীত ক্রমে তাদের প্রকাশ করে।


আপনি কি দয়া করে Using.resourceভেরিয়েন্টটি যুক্ত করতে পারেন ?
ড্যানিয়েল সি সোব্রাল

@ ড্যানিয়েলসি.সোব্রাল, নিশ্চিতভাবে স্রেফ এটি যুক্ত করেছেন।
চেঙ্গপাহী

আপনি কিভাবে স্কাল 2.12 এর জন্য এটি লিখবেন? এখানে একটি অনুরূপ usingপদ্ধতি:def using[A <: AutoCloseable, B](resource: A) (block: A => B): B = try block(resource) finally resource.close()
মাইক স্লিন

75

ক্রিস হ্যানসেনের ব্লগ এন্ট্রি 'স্কালায় এআরএম ব্লক: রিভিসিটেড' মার্টিন ওডারস্কির ফসডেম উপস্থাপনার 21 স্লাইড সম্পর্কে আলোচনা করেছে । এই পরবর্তী ব্লকটি 21 স্লাইড থেকে সরাসরি নেওয়া হয়েছে (অনুমতি সহ):

def using[T <: { def close() }]
    (resource: T)
    (block: T => Unit) 
{
  try {
    block(resource)
  } finally {
    if (resource != null) resource.close()
  }
}

- শেষ উদ্ধৃতি--

তারপরে আমরা এ জাতীয় কল করতে পারি:

using(new BufferedReader(new FileReader("file"))) { r =>
  var count = 0
  while (r.readLine != null) count += 1
  println(count)
}

এই পদ্ধতির ত্রুটিগুলি কী কী? এই প্যাটার্নটি যেখানে আমার স্বয়ংক্রিয় সংস্থান ব্যবস্থাপনার প্রয়োজন হবে তার 95% সম্বোধন করবে ...

সম্পাদনা করুন: কোড স্নিপেট যুক্ত


সম্পাদনা 2: ডিজাইনের ধরণ বাড়ানো - অজগর withবিবৃতি থেকে অনুপ্রেরণা গ্রহণ এবং সম্বোধন:

  • ব্লক আগে চালানো বিবৃতি
  • পরিচালিত সংস্থান উপর নির্ভর করে পুনরায় নিক্ষেপ ব্যতিক্রম
  • একটি একক ব্যবহারের বিবৃতি দিয়ে দুটি সংস্থান হ্যান্ডলিং
  • একটি অন্তর্নিহিত রূপান্তর এবং একটি Managedক্লাস সরবরাহ করে রিসোর্স-নির্দিষ্ট হ্যান্ডলিং

এটি স্কেলা ২.৮ এর সাথে।

trait Managed[T] {
  def onEnter(): T
  def onExit(t:Throwable = null): Unit
  def attempt(block: => Unit): Unit = {
    try { block } finally {}
  }
}

def using[T <: Any](managed: Managed[T])(block: T => Unit) {
  val resource = managed.onEnter()
  var exception = false
  try { block(resource) } catch  {
    case t:Throwable => exception = true; managed.onExit(t)
  } finally {
    if (!exception) managed.onExit()
  }
}

def using[T <: Any, U <: Any]
    (managed1: Managed[T], managed2: Managed[U])
    (block: T => U => Unit) {
  using[T](managed1) { r =>
    using[U](managed2) { s => block(r)(s) }
  }
}

class ManagedOS(out:OutputStream) extends Managed[OutputStream] {
  def onEnter(): OutputStream = out
  def onExit(t:Throwable = null): Unit = {
    attempt(out.close())
    if (t != null) throw t
  }
}
class ManagedIS(in:InputStream) extends Managed[InputStream] {
  def onEnter(): InputStream = in
  def onExit(t:Throwable = null): Unit = {
    attempt(in.close())
    if (t != null) throw t
  }
}

implicit def os2managed(out:OutputStream): Managed[OutputStream] = {
  return new ManagedOS(out)
}
implicit def is2managed(in:InputStream): Managed[InputStream] = {
  return new ManagedIS(in)
}

def main(args:Array[String]): Unit = {
  using(new FileInputStream("foo.txt"), new FileOutputStream("bar.txt")) { 
    in => out =>
    Iterator continually { in.read() } takeWhile( _ != -1) foreach { 
      out.write(_) 
    }
  }
}

2
বিকল্প আছে, কিন্তু আমি বোঝাতে চাইছি না যে এখানে কিছু ভুল আছে। স্ট্যাক ওভারফ্লোতে আমি কেবল এখানে সমস্ত উত্তরগুলি চাই। :-)
ড্যানিয়েল সি সোব্রাল

5
আপনি কি জানেন যে স্ট্যান্ডার্ড এপিআই তে এরকম কিছু আছে কিনা? আমার নিজের জন্য সারাক্ষণ এটি লিখতে হবে এমন এক রজনী মনে হয়।
ড্যানিয়েল দারাবস

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

যদি ব্লকটি একটি পুনরুক্তি ফেরত দেয় আপনি কীভাবে এটি করার পরামর্শ দিচ্ছেন?
জর্গে মাচাডো

62

ড্যানিয়েল,

আমি স্বয়ংক্রিয়ভাবে রিসোর্স ব্যবস্থাপনার জন্য সম্প্রতি স্কাল-আর্ম লাইব্রেরি মোতায়েন করেছি। আপনি এখানে ডকুমেন্টেশন খুঁজে পেতে পারেন: https://github.com/jsuereth/scala-arm/wiki

এই গ্রন্থাগারটি তিনটি ব্যবহারের শৈলী সমর্থন করে (বর্তমানে):

1) আবশ্যক / প্রকাশের জন্য:

import resource._
for(input <- managed(new FileInputStream("test.txt")) {
// Code that uses the input as a FileInputStream
}

2) মোনাডিক-স্টাইল

import resource._
import java.io._
val lines = for { input <- managed(new FileInputStream("test.txt"))
                  val bufferedReader = new BufferedReader(new InputStreamReader(input)) 
                  line <- makeBufferedReaderLineIterator(bufferedReader)
                } yield line.trim()
lines foreach println

3) বিস্মৃত ধারাবাহিকতা-স্টাইল

এখানে একটি "প্রতিধ্বনি" টিসিপি সার্ভার রয়েছে:

import java.io._
import util.continuations._
import resource._
def each_line_from(r : BufferedReader) : String @suspendable =
  shift { k =>
    var line = r.readLine
    while(line != null) {
      k(line)
      line = r.readLine
    }
  }
reset {
  val server = managed(new ServerSocket(8007)) !
  while(true) {
    // This reset is not needed, however the  below denotes a "flow" of execution that can be deferred.
    // One can envision an asynchronous execuction model that would support the exact same semantics as below.
    reset {
      val connection = managed(server.accept) !
      val output = managed(connection.getOutputStream) !
      val input = managed(connection.getInputStream) !
      val writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(output)))
      val reader = new BufferedReader(new InputStreamReader(input))
      writer.println(each_line_from(reader))
      writer.flush()
    }
  }
}

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


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

18

ধারাবাহিকতা ব্যবহার করে এখানে জেমস আইরি সমাধান:

// standard using block definition
def using[X <: {def close()}, A](resource : X)(f : X => A) = {
   try {
     f(resource)
   } finally {
     resource.close()
   }
}

// A DC version of 'using' 
def resource[X <: {def close()}, B](res : X) = shift(using[X, B](res))

// some sugar for reset
def withResources[A, C](x : => A @cps[A, C]) = reset{x}

তুলনার জন্য ধারাবাহিকতা ছাড়াই এবং ছাড়াই এখানে সমাধানগুলি রয়েছে:

def copyFileCPS = using(new BufferedReader(new FileReader("test.txt"))) {
  reader => {
   using(new BufferedWriter(new FileWriter("test_copy.txt"))) {
      writer => {
        var line = reader.readLine
        var count = 0
        while (line != null) {
          count += 1
          writer.write(line)
          writer.newLine
          line = reader.readLine
        }
        count
      }
    }
  }
}

def copyFileDC = withResources {
  val reader = resource[BufferedReader,Int](new BufferedReader(new FileReader("test.txt")))
  val writer = resource[BufferedWriter,Int](new BufferedWriter(new FileWriter("test_copy.txt")))
  var line = reader.readLine
  var count = 0
  while(line != null) {
    count += 1
    writer write line
    writer.newLine
    line = reader.readLine
  }
  count
}

এবং এখানে টিয়ার্ক রম্প্ফের উন্নতির পরামর্শ:

trait ContextType[B]
def forceContextType[B]: ContextType[B] = null

// A DC version of 'using'
def resource[X <: {def close()}, B: ContextType](res : X): X @cps[B,B] = shift(using[X, B](res))

// some sugar for reset
def withResources[A](x : => A @cps[A, A]) = reset{x}

// and now use our new lib
def copyFileDC = withResources {
 implicit val _ = forceContextType[Int]
 val reader = resource(new BufferedReader(new FileReader("test.txt")))
 val writer = resource(new BufferedWriter(new FileWriter("test_copy.txt")))
 var line = reader.readLine
 var count = 0
 while(line != null) {
   count += 1
   writer write line
   writer.newLine
   line = reader.readLine
 }
 count
}

বাফারড্রাইটার কনস্ট্রাক্টর ব্যর্থ হলে (নতুন বাফারড্রাইটার (নতুন ফাইল রাইটার ("টেস্ট_কপি.টেক্সট"))) ব্যবহার করে না? প্রতিটি সংস্থান ব্যবহারের ব্লকে আবদ্ধ করা উচিত ...
জাপ

@ যাপ এটি ওরাকল দ্বারা প্রস্তাবিত স্টাইল । BufferedWriterচেক করা ব্যতিক্রমগুলি ফেলে দেয় না, সুতরাং যদি কোনও ব্যতিক্রম ছুঁড়ে দেওয়া হয় তবে প্রোগ্রামটি এটি থেকে সেরে উঠবে বলে আশা করা যায় না।
ড্যানিয়েল সি সোব্রাল

7

আমি স্কালায় এআরএম করার জন্য ধীরে ধীরে 4 ধাপের বিবর্তন দেখতে পাচ্ছি:

  1. কোনও এআরএম নয়: ময়লা
  2. কেবল ক্লোজার: আরও ভাল তবে একাধিক নেস্টেড ব্লক
  3. ধারাবাহিকতা মোনাড: 2 টি ব্লকে বাসা বাঁধতে, তবে অপ্রাকৃতভাবে পৃথক করার জন্য ব্যবহার করুন
  4. সরাসরি শৈলীর ধারাবাহিকতা: নীরবা, আহা! এটি সর্বাধিক প্রকারের নিরাপদ বিকল্প: রিসোর্স ব্লক সহ বাইরের একটি সংস্থান টাইপ ত্রুটি হবে।

1
মনে মনে, স্কালায় সিপিএস মনডের মাধ্যমে প্রয়োগ করা হয়। :-)
ড্যানিয়েল সি সোব্রাল

1
মুশতাক, ৩) আপনি একটি মোনাডে রিসোর্স ম্যানেজমেন্ট করতে পারেন যা ধারাবাহিকতার মোড নয় 4) আমার সাথে রিসোর্স ম্যানেজমেন্ট / রিসোর্স ডিলিমিটেড কনটেইনস কোড ব্যবহার করা "ব্যবহারের" চেয়ে আর ((কম নয়) প্রকারের নিরাপদ নয়। এটি প্রয়োজন এমন কোনও সংস্থান পরিচালনা করতে ভুলে যাওয়া এখনও সম্ভব। (নতুন রিসোর্স ()) ব্যবহার করে তুলনা করুন {প্রথম => ভাল দ্বিতীয় = নতুন রিসোর্স () // ওফ! // রিসোর্স ব্যবহার করুন first // কেবল প্রথমে রিসোর্স দিয়ে বন্ধ হয়ে যায় {ভাল প্রথম = রিসোর্স (নতুন রিসোর্স ()) ভাল সেকেন্ড = নতুন রিসোর্স () // ওফ! // রিসোর্স ব্যবহার করুন ...} // কেবল প্রথম বন্ধ হয়ে যায়
জেমস আইরি

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

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

6

আরও ভাল-ফাইলগুলির সাথে হালকা ওজন (কোডের 10 টি লাইন) এআরএম অন্তর্ভুক্ত রয়েছে। দেখুন: https://github.com/pathikrit/better-files#lightweight-arm

import better.files._
for {
  in <- inputStream.autoClosed
  out <- outputStream.autoClosed
} in.pipeTo(out)
// The input and output streams are auto-closed once out of scope

আপনি যদি পুরো লাইব্রেরিটি না চান তবে এটি কীভাবে প্রয়োগ করা হবে তা এখানে:

  type Closeable = {
    def close(): Unit
  }

  type ManagedResource[A <: Closeable] = Traversable[A]

  implicit class CloseableOps[A <: Closeable](resource: A) {        
    def autoClosed: ManagedResource[A] = new Traversable[A] {
      override def foreach[U](f: A => U) = try {
        f(resource)
      } finally {
        resource.close()
      }
    }
  }

এটা বেশ সুন্দর। আমি এই পদ্ধতির অনুরূপ কিছু নিয়েছি তবে পূর্বাবস্থার পরিবর্তে ক্লোজবেল আপসের জন্য একটি mapএবং flatMapপদ্ধতিটি সংজ্ঞায়িত করেছি যাতে বোঝার জন্য কোনও ট্র্যাজেবল ফলন না হয়।
এজক্যাসবার্গ

1

প্রকারের ক্লাসগুলি কীভাবে ব্যবহার করবেন

trait GenericDisposable[-T] {
   def dispose(v:T):Unit
}
...

def using[T,U](r:T)(block:T => U)(implicit disp:GenericDisposable[T]):U = try {
   block(r)
} finally { 
   Option(r).foreach { r => disp.dispose(r) } 
}

1

অন্য বিকল্প হ'ল চপ্পির অলস ট্রাই ক্লোজ মোনাড। এটি ডাটাবেস সংযোগগুলি সহ বেশ ভাল:

val ds = new JdbcDataSource()
val output = for {
  conn  <- TryClose(ds.getConnection())
  ps    <- TryClose(conn.prepareStatement("select * from MyTable"))
  rs    <- TryClose.wrap(ps.executeQuery())
} yield wrap(extractResult(rs))

// Note that Nothing will actually be done until 'resolve' is called
output.resolve match {
    case Success(result) => // Do something
    case Failure(e) =>      // Handle Stuff
}

এবং স্ট্রিম সহ:

val output = for {
  outputStream      <- TryClose(new ByteArrayOutputStream())
  gzipOutputStream  <- TryClose(new GZIPOutputStream(outputStream))
  _                 <- TryClose.wrap(gzipOutputStream.write(content))
} yield wrap({gzipOutputStream.flush(); outputStream.toByteArray})

output.resolve.unwrap match {
  case Success(bytes) => // process result
  case Failure(e) => // handle exception
}

এখানে আরও তথ্য: https://github.com/choppythelumberjack/tryclose


0

এখানে @ চেংপোহির জবাব রয়েছে, এটি পরিবর্তিত হয়েছে সুতরাং এটি স্কাল ২.১৩ এর পরিবর্তে স্কেল ২.৮++ এর সাথে কাজ করে (হ্যাঁ, এটি স্কালা ২.১13 এর সাথেও কাজ করে):

def unfold[A, S](start: S)(op: S => Option[(A, S)]): List[A] =
  Iterator
    .iterate(op(start))(_.flatMap{ case (_, s) => op(s) })
    .map(_.map(_._1))
    .takeWhile(_.isDefined)
    .flatten
    .toList

def using[A <: AutoCloseable, B](resource: A)
                                (block: A => B): B =
  try block(resource) finally resource.close()

val lines: Seq[String] =
  using(new BufferedReader(new FileReader("file.txt"))) { reader =>
    unfold(())(_ => Option(reader.readLine()).map(_ -> ())).toList
  }
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.