Elixir-프로세스

Elixir에서 모든 코드는 프로세스 내에서 실행됩니다. 프로세스는 서로 격리되고 동시에 실행되며 메시지 전달을 통해 통신합니다. Elixir의 프로세스를 운영 체제 프로세스와 혼동해서는 안됩니다. Elixir의 프로세스는 메모리와 CPU 측면에서 매우 가볍습니다 (다른 프로그래밍 언어의 스레드와 달리). 이 때문에 수만 또는 수십만 개의 프로세스를 동시에 실행하는 것은 드문 일이 아닙니다.

이 장에서는 새 프로세스를 생성하고 서로 다른 프로세스간에 메시지를 보내고 받기위한 기본 구조에 대해 알아 봅니다.

스폰 기능

새 프로세스를 만드는 가장 쉬운 방법은 spawn함수. 그만큼spawn새 프로세스에서 실행될 함수를 허용합니다. 예를 들면-

pid = spawn(fn -> 2 * 2 end)
Process.alive?(pid)

위의 프로그램이 실행되면 다음과 같은 결과가 생성됩니다.

false

spawn 함수의 반환 값은 PID입니다. 이것은 프로세스의 고유 식별자이므로 PID 위의 코드를 실행하면 달라집니다. 이 예에서 볼 수 있듯이 프로세스가 살아 있는지 확인하면 프로세스가 종료됩니다. 이는 주어진 함수 실행이 완료되는 즉시 프로세스가 종료되기 때문입니다.

이미 언급했듯이 모든 Elixir 코드는 프로세스 내부에서 실행됩니다. self 함수를 실행하면 현재 세션에 대한 PID가 표시됩니다.

pid = self
 
Process.alive?(pid)

위의 프로그램이 실행되면 다음과 같은 결과가 생성됩니다.

true

메시지 전달

프로세스에 메시지를 보낼 수 있습니다. send 그리고 그들을 받아 receive. 현재 프로세스에 메시지를 전달하고 동일한 메시지를 수신하겠습니다.

send(self(), {:hello, "Hi people"})

receive do
   {:hello, msg} -> IO.puts(msg)
   {:another_case, msg} -> IO.puts("This one won't match!")
end

위의 프로그램이 실행되면 다음과 같은 결과가 생성됩니다.

Hi people

send 함수를 사용하여 현재 프로세스에 메시지를 보내고 self의 PID에 전달했습니다. 그런 다음 수신 메시지를receive 함수.

메시지가 프로세스로 전송되면 메시지는 process mailbox. 수신 블록은 주어진 패턴과 일치하는 메시지를 검색하는 현재 프로세스 사서함을 통과합니다. 수신 블록은 가드와 case와 같은 많은 절을 지원합니다.

패턴과 일치하는 메일 박스에 메시지가없는 경우 현재 프로세스는 일치하는 메시지가 도착할 때까지 대기합니다. 제한 시간도 지정할 수 있습니다. 예를 들면

receive do
   {:hello, msg}  -> msg
after
   1_000 -> "nothing after 1s"
end

위의 프로그램이 실행되면 다음과 같은 결과가 생성됩니다.

nothing after 1s

NOTE − 메시지가 이미 사서함에있을 것으로 예상하는 경우 시간 초과 0을 지정할 수 있습니다.

연결

Elixir에서 가장 일반적인 스폰 형태는 실제로 spawn_link함수. spawn_link를 사용한 예제를 살펴보기 전에 프로세스가 실패 할 때 어떤 일이 발생하는지 이해합시다.

spawn fn -> raise "oops" end

위의 프로그램이 실행되면 다음과 같은 오류가 발생합니다.

[error] Process #PID<0.58.00> raised an exception
** (RuntimeError) oops
   :erlang.apply/2

오류를 기록했지만 생성 프로세스가 여전히 실행 중입니다. 프로세스가 분리되어 있기 때문입니다. 한 프로세스의 실패를 다른 프로세스로 전파하려면 연결해야합니다. 이것은spawn_link함수. 같은 것을 이해하는 예를 고려해 보겠습니다.

spawn_link fn -> raise "oops" end

위의 프로그램이 실행되면 다음과 같은 오류가 발생합니다.

** (EXIT from #PID<0.41.0>) an exception was raised:
   ** (RuntimeError) oops
      :erlang.apply/2

이것을 실행하는 경우 iex그러면 쉘은이 오류를 처리하고 종료하지 않습니다. 그러나 먼저 스크립트 파일을 만든 다음elixir <file-name>.exs,이 실패로 인해 상위 프로세스도 중단됩니다.

내결함성 시스템을 구축 할 때 프로세스와 링크가 중요한 역할을합니다. Elixir 애플리케이션에서 우리는 종종 프로세스가 죽을 때를 감지하고 그 자리에서 새로운 프로세스를 시작하는 감독자와 프로세스를 연결합니다. 이는 프로세스가 격리되어 있고 기본적으로 아무것도 공유하지 않기 때문에 가능합니다. 그리고 프로세스가 격리되어 있기 때문에 프로세스의 실패가 다른 프로세스의 상태를 손상 시키거나 손상시킬 수있는 방법은 없습니다. 다른 언어에서는 예외를 포착 / 처리해야합니다. Elixir에서는 감독자가 시스템을 올바르게 다시 시작하기를 기대하기 때문에 프로세스가 실패하도록 허용하는 것이 좋습니다.

상태

예를 들어 애플리케이션 구성을 유지하기 위해 상태가 필요한 애플리케이션을 빌드하거나 파일을 구문 분석하고 메모리에 보관해야하는 경우 어디에 저장 하시겠습니까? Elixir의 프로세스 기능은 이러한 작업을 수행 할 때 유용 할 수 있습니다.

무한 루프, 상태 유지, 메시지 송수신 프로세스를 작성할 수 있습니다. 예를 들어, 이름이 지정된 파일에서 키-값 저장소로 작동하는 새 프로세스를 시작하는 모듈을 작성해 보겠습니다.kv.exs.

defmodule KV do
   def start_link do
      Task.start_link(fn -> loop(%{}) end)
   end

   defp loop(map) do
      receive do
         {:get, key, caller} ->
         send caller, Map.get(map, key)
         loop(map)
         {:put, key, value} ->
         loop(Map.put(map, key, value))
      end
   end
end

참고 start_link 함수는 다음을 실행하는 새 프로세스를 시작합니다. loop빈지도로 시작하는 함수입니다. 그만큼loop그런 다음 함수는 메시지를 기다리고 각 메시지에 대해 적절한 작업을 수행합니다. 의 경우:get메시지를 보내면 호출자에게 메시지를 다시 보내고 루프를 다시 호출하여 새 메시지를 기다립니다. 동안:put 메시지가 실제로 호출 loop 주어진 키와 값이 저장된지도의 새 버전으로.

이제 다음을 실행 해 보겠습니다.

iex kv.exs

이제 당신은 당신의 iex껍질. 모듈을 테스트하려면 다음을 시도하십시오.

{:ok, pid} = KV.start_link

# pid now has the pid of our new process that is being 
# used to get and store key value pairs 

# Send a KV pair :hello, "Hello" to the process
send pid, {:put, :hello, "Hello"}

# Ask for the key :hello
send pid, {:get, :hello, self()}

# Print all the received messages on the current process.
flush()

위의 프로그램이 실행되면 다음과 같은 결과가 생성됩니다.

"Hello"