programing tip

스칼라 배우 : 수신 대 반응

itbloger 2020. 8. 2. 17:40
반응형

스칼라 배우 : 수신 대 반응


먼저 Java 경험이 많지만 최근에는 기능적 언어에 관심을 갖게되었다고 말하겠습니다. 최근에 저는 스칼라를보기 시작했습니다. 아주 좋은 언어 인 것 같습니다.

그러나 Scala의 Programming에서 Scala 의 Actor 프레임 워크에 대해 읽었 으며 이해할 수없는 것이 있습니다. 30.4 장에서는 쓰레드 react대신 receive재사용하면 쓰레드를 재사용 할 수있게되는데, 이는 쓰레드가 JVM에서 비싸기 때문에 성능에 좋습니다.

이것은 react대신에 전화 하는 것을 기억 하는 한 receive, 내가 원하는만큼 많은 액터를 시작할 수 있다는 것을 의미합니까 ? Scala를 발견하기 전에 Erlang과 함께 놀고 있었고 Programming Erlang 의 저자 는 땀을 흘리지 않고 200,000 개 이상의 프로세스를 생성하는 것을 자랑 스럽게 생각 합니다. Java 스레드로 그렇게하는 것이 싫습니다. Erlang (및 Java)과 비교하여 Scala에서 어떤 제한을보고 있습니까?

또한이 스레드는 Scala에서 어떻게 작동합니까? 단순화를 위해 하나의 스레드 만 있다고 가정 해 봅시다. 이 스레드에서 시작한 모든 액터가 순차적으로 실행됩니까? 아니면 일종의 작업 전환이 발생합니까? 예를 들어 서로 메시지를 핑퐁하는 두 명의 액터를 시작하면 같은 스레드에서 시작되면 교착 상태가 발생할 위험이 있습니까?

Scala의 Programming에 따르면 , 사용할 액터를 작성하는 react것이보다 어렵습니다 receive. react돌아 오지 않기 때문에 그럴듯하게 들립니다 . 그러나이 책은을 react사용하여 루프 안에 넣을 수있는 방법을 보여줍니다 Actor.loop. 결과적으로

loop {
    react {
        ...
    }
}

나에게 꽤 비슷한 것 같습니다

while (true) {
    receive {
        ...
    }
}

이 책의 앞부분에서 사용됩니다. 그럼에도 불구하고이 책은 "실제로 프로그램은 최소한 몇 개가 필요하다"고 말합니다 receive. 그래서 여기서 무엇을 놓치고 있습니까? 무엇을 할 수 receive그렇게 react반환 외에, 수 없습니다를? 왜 신경 쓰나요?

마지막으로, 내가 이해하지 못하는 것의 핵심에 이르렀습니다.이 책을 react사용하면 스레드를 재사용하기 위해 호출 스택을 버릴 수 있는 방법에 대해 언급합니다 . 어떻게 작동합니까? 호출 스택을 폐기해야하는 이유는 무엇입니까? 그리고 함수가 예외 ( react) 를 던져서 종료 될 때 호출 스택을 버릴 수는 있지만 ( receive) 를 반환하여 종료 될 때가 아닌 이유는 무엇입니까?

Scala의 Programming이 여기에있는 주요 문제 중 일부를 고집하고 있다는 인상을 받았습니다. 그렇지 않으면 정말 훌륭한 책이기 때문에 부끄러운 일입니다.


먼저 기다리는 각 액터 receive가 스레드를 점유합니다. 아무것도 수신하지 않으면 해당 스레드는 아무것도 수행하지 않습니다. 액터 온 react은 무언가를받을 때까지 스레드를 차지하지 않습니다. 무언가를 받으면 스레드가 할당되어 초기화됩니다.

이제 초기화 부분이 중요합니다. 수신 스레드는 무언가를 리턴 할 것으로 예상되며 반응 스레드는 그렇지 않습니다. 따라서 마지막 끝의 이전 스택 상태 react는 완전히 폐기 될 수 있습니다. 스택 상태를 저장하거나 복원 할 필요가 없으므로 스레드를 더 빨리 시작할 수 있습니다.

하나 또는 다른 것을 원하는 여러 가지 성능 이유가 있습니다. 아시다시피, Java에서 너무 많은 스레드를 갖는 것은 좋은 생각이 아닙니다. 반면에 액터를 스레드에 첨부하기 전에 액터를 첨부해야하기 때문에 메시지보다 메시지에 react더 빠릅니다 . 따라서 많은 메시지를 수신하지만 그와 관련이 거의없는 액터가있는 경우 추가 지연으로 인해 목적에 따라 속도가 너무 느려질 수 있습니다.receivereactreact


정답은 "예"입니다. 액터가 코드의 어떤 것도 차단하지 않고을 사용 하는 경우 단일 스레드 내에서 "동시" 프로그램을 react실행할 수 있습니다 (시스템 속성 설정하여 시도하십시오 ).actors.maxPoolSize

왜 더 분명 이유 중 하나 호출 스택을 폐기 할 필요는 그렇지 않은 것입니다 loop방법은 끝나는 것입니다 StackOverflowError. 그대로, 프레임 워크는 a react를 던지면서 영리하게 a 끝내고 SuspendActorException, 이는 루핑 코드에 의해 잡히고 메소드 react를 통해 다시 실행됩니다 andThen.

mkBody메소드를 살펴본 Actor다음 seq루프가 어떻게 재조정되는지 확인하는 방법을 살펴보십시오.


"스택 폐기"에 대한 진술은 잠시 동안 혼란 스러웠으며 지금 당장 이해하고 있다고 생각합니다. "수신"의 경우, 메시지에 대한 전용 스레드 차단 (모니터에서 object.wait () 사용)이 있으며 이는 전체 스레드 스택을 사용할 수 있으며 수신 대기 중 "대기"시점부터 계속할 수 있음을 의미 메시지. 예를 들어 다음 코드가 있다면

  def a = 10;
  while (! done)  {
     receive {
        case msg =>  println("MESSAGE RECEIVED: " + msg)
     }
     println("after receive and printing a " + a)
  }

스레드는 메시지가 수신 될 때까지 수신 호출에서 대기 한 다음 계속해서 "10을 받고 인쇄 한 후"메시지와 스레드가 차단되기 전에 스택 프레임에있는 "10"값을 인쇄합니다.

반응하는 경우 그러한 전용 스레드가없는 경우, react 메서드의 전체 메소드 본문은 클로저로 캡처되어 메시지를 수신하는 해당 액터의 임의의 스레드에 의해 실행됩니다. 즉, 클로저만으로 캡처 할 수있는 명령문 만 실행되며 리턴 유형 "Nothing"이 실행됩니다. 다음 코드를 고려하십시오

  def a = 10;
  while (! done)  {
     react {
        case msg =>  println("MESSAGE RECEIVED: " + msg)
     }
     println("after react and printing a " + a) 
  }

If react had a return type of void, it would mean that it is legal to have statements after the "react" call ( in the example the println statement that prints the message "after react and printing a 10"), but in reality that would never get executed as only the body of the "react" method is captured and sequenced for execution later (on the arrival of a message). Since the contract of react has the return type of "Nothing" there cannot be any statements following react, and there for there is no reason to maintain the stack. In the example above variable "a" would not have to be maintained as the statements after the react calls are not executed at all. Note that all the needed variables by the body of react is already be captured as a closure, so it can execute just fine.

The java actor framework Kilim actually does the stack maintenance by saving the stack which gets unrolled on the react getting a message.


Just to have it here:

Event-Based Programming without Inversion of Control

These papers are linked from the scala api for Actor and provide the theoretical framework for the actor implementation. This includes why react may never return.


I haven't done any major work with scala /akka, however i understand that there is a very significant difference in the way actors are scheduled. Akka is just a smart threadpool which is time slicing execution of actors... Every time slice will be one message execution to completion by an actor unlike in Erlang which could be per instruction?!

This leads me to think that react is better as it hints the current thread to consider other actors for scheduling where as receive "might" engage the current thread to continue executing other messages for the same actor.

참고URL : https://stackoverflow.com/questions/1251666/scala-actors-receive-vs-react

반응형