복붙노트

[SCALA] 스칼라 무엇 자동 자원 관리 대안을 존재 하는가?

SCALA

스칼라 무엇 자동 자원 관리 대안을 존재 하는가?

나는 스칼라에 대한 웹에 ARM (자동 자원 관리)의 많은 예제를 보았다. 대부분의 모습 불구하고 거의 서로 같은, 쓰기 하나에 의식-의 통로가 될 것으로 보인다. 그래도, 연속 요청을 사용하여 정말 멋진 예제를 참조했다.

어쨌든, 그 많은 코드가 한 종류 또는 다른의 결함을 가지고, 내가 여기에 우리가 가장 정확하고 적절한 버전을 투표 할 수 스택 오버플로에 대한 참조를 가지고 좋은 아이디어라고 생각 때문에.

해결법

  1. ==============================

    1.지금 스칼라 2.13 마지막으로 지원하고 경우 : :) 예를 사용하여 사용하여 자원을 시도 :

    지금 스칼라 2.13 마지막으로 지원하고 경우 : :) 예를 사용하여 사용하여 자원을 시도 :

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

    또는 Using.resource 않도록 시도를 사용하여

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

    당신은 문서를 사용하여 더 많은 예를 찾을 수 있습니다.

  2. ==============================

    2.크리스 한센의 블로그 항목 : 마틴 오더 스키의 FOSDEM 프레 젠 테이션의 슬라이드 (21)에 대해에 대해 3/26/09 회담에서 '스칼라에서 ARM 블록은 재 방문'. 이 다음 블록은 직선 슬라이드 (21) (허가)에서 가져온 것입니다 :

    크리스 한센의 블로그 항목 : 마틴 오더 스키의 FOSDEM 프레 젠 테이션의 슬라이드 (21)에 대해에 대해 3/26/09 회담에서 '스칼라에서 ARM 블록은 재 방문'. 이 다음 블록은 직선 슬라이드 (21) (허가)에서 가져온 것입니다 :

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

    --end quote--

    그럼 우리는 다음과 같이 호출 할 수 있습니다 :

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

    이 방법의 단점은 무엇입니까? 그 패턴은 내가 자동 자원 관리를 필요 곳의 95 %를 해결하는 것 같다 ...

    편집 : 추가 코드

    EDIT2 : 디자인 패턴을 확장 - 성명 및 주소와 파이썬에서 영감을 복용 :

    이 스칼라 2.8입니다.

    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(_) 
        }
      }
    }
    
  3. ==============================

    3.다니엘,

    다니엘,

    나는 최근에 자동 자원 관리를위한 스칼라 팔 라이브러리를 구축했습니다. 현재 문서를 찾을 수 있습니다 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) 구분 Continuations를 스타일

    여기에 "에코"TCP 서버는 다음과 같습니다

    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()
        }
      }
    }
    

    그것은 대부분의 자원 유형에 적응할 수 그래서 코드는 자원 유형 형질의 사용을합니다. 이는 근접 또는 폐기 방법 중 어느 클래스에 대해 입력 구조를 사용할 수있는 대체 수단을 갖는다. 설명서를 확인하고 추가 할 수있는 편리한 기능을 생각하면 알려 주시기 바랍니다.

  4. ==============================

    4.여기에 연속 요청을 사용하여 제임스 Iry 솔루션입니다 :

    여기에 연속 요청을 사용하여 제임스 Iry 솔루션입니다 :

    // 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
    }
    

    그리고 여기 개선 Tiark Rompf의 제안이다 :

    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
    }
    
  5. ==============================

    5.나는 스칼라에서 ARM을 수행하기위한 점진적인 4 단계의 진화를 참조하십시오

    나는 스칼라에서 ARM을 수행하기위한 점진적인 4 단계의 진화를 참조하십시오

  6. ==============================

    6.더 나은 파일에 포함 된 ARM 가벼운 무게 (코드 10 개 라인)가있다. 참조 : https://github.com/pathikrit/better-files#lightweight-arm

    더 나은 파일에 포함 된 ARM 가벼운 무게 (코드 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()
          }
        }
      }
    
  7. ==============================

    7.어떻게 유형 클래스를 사용하는 방법에 대한

    어떻게 유형 클래스를 사용하는 방법에 대한

    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) } 
    }
    
  8. ==============================

    8.또 다른 대안은 고르지의 게으른 TryClose 모나드이다. 그것은 데이터베이스 연결 꽤 좋은 :

    또 다른 대안은 고르지의 게으른 TryClose 모나드이다. 그것은 데이터베이스 연결 꽤 좋은 :

    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

  9. ==============================

    9.여기 대신, 그것은 스칼라 2.8 이상에서 작동되도록 수정 chengpohi의 대답 @ 스칼라 2.13 (예, 그것은 또한 스칼라 2.13와 함께 작동)입니다 :

    여기 대신, 그것은 스칼라 2.8 이상에서 작동되도록 수정 chengpohi의 대답 @ 스칼라 2.13 (예, 그것은 또한 스칼라 2.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
      }
    
  10. from https://stackoverflow.com/questions/2207425/what-automatic-resource-management-alternatives-exist-for-scala by cc-by-sa and MIT license