2016-09-01 14 views
0

私はエリクシールで遊んで始めました。私は2つのモジュールを作りたいと思っていました。 1つは、メッセージを入力して、それがメッセージを受け取ったことを認める他のプログラムにメッセージを送り、最初のプログラムがメッセージを印刷するように促すメッセージです。エリクシールプロセスからコンソールに印刷

まあ、私は問題に出くわしました。

送信者は以下の通りです:

defmodule PracticeCaller do 
    def start do 
     spawn(&sloop/0) 
    end 

    def sloop do 
     pid = :erlang.spawn(&PracticeServer.start/0) 
     message = IO.gets "Enter a message:" 
     send(pid, {self, message}) 
     receive do 
      {_caller, reply} -> IO.puts "#{reply}" 
     end 
     sloop 
    end 
end 

と受信機はここにある:

defmodule PracticeServer do 
    def start do 
     spawn(&loop/0) 
    end 

    defp loop do 
     receive do 
      {caller, "kill"} -> send(caller, {self, "Process Dead"}) 
       Process.exit(self, :kill) 
      {caller, _} -> send(caller, {self, "Thank you for your message!"})  
     end 

     loop  
    end 

end 

私の最初の問題は、私は私の送信者ループを開始すると、端末がメッセージを入力するように私を促していることで、受信したメッセージは印刷されません。

第2に、「kill」と入力すると、ターミナルがフリーズします。なぜなら、私は:kill応答を処理する方法がわからないからです。

これらの問題の修正に関するヘルプはありますか?

+0

サーバーの終了後にクライアントが何をしたいですか? – Dogbert

+0

私はクライアントも殺されることを望みますが、私はそれをどうやって行うのか分かりません。 – Mascasc

答えて

3

最初の問題は、次のとおりです。

pid = :erlang.spawn(&PracticeServer.start/0) 

PracticeServer.start/0が再びspawnを呼び出しているという事実。つまり、pidPracticeServer.loop/0を実行しているプロセスを参照していませんが、すぐに終了したのはPracticeServer.loop/0というプロセスです。私が変更した場合は

pid = :erlang.spawn(&PracticeServer.start/0) 

だけに:

pid = PracticeServer.start 

いくつかのものは、作業を開始:

Enter a message:hello 
Thank you for your message! 
Enter a message:world 
Thank you for your message! 

しかし:

Enter a message:kill 
Thank you for your message! 

IO.gets/1には改行文字が含まれています。つまり、{caller, "kill"}のパターンがPracticeServer.loop/0と一致しないことを意味します。今

message = IO.gets "Enter a message:" 

message = IO.gets("Enter a message:") |> String.trim_trailing 

へ:

Enter a message:kill 
Process Dead 
Enter a message:kill 
Process Dead 

もう一つの問題は、あなたが現在のプロセスを漏洩していることである

これは変更することで固定することができます。スポーンされたサーバーを再利用する代わりに、すべてのメッセージに対して新しいサーバーを作成します。また、 "kill"することができる再帰的なreceiveを処理する慣用的な方法は、プロセスを終了させたいときに再帰呼び出しを行わないことです。

defmodule PracticeCaller do 
    def start do 
    spawn(fn -> loop(PracticeServer.start) end) 
    end 

    def loop(server) do 
    message = IO.gets("Enter a message: ") |> String.trim_trailing 
    send(server, {self, message}) 
    receive do 
     {_caller, reply} -> 
     IO.puts "#{reply}" 
     # Only continue if process is not dead. 
     # Comparing against strings is usually not idiomatic, you may want to 
     # change that. 
     if reply != "Process Dead" do 
      loop(server) 
     end 
    end 
    end 
end 

defmodule PracticeServer do 
    def start do 
    spawn(&loop/0) 
    end 

    def loop do 
    receive do 
     {caller, "kill"} -> 
     send(caller, {self, "Process Dead"}) 
     {caller, _} -> 
     send(caller, {self, "Thank you for your message!"})  
     loop  
    end 
    end 
end 

PracticeCaller.start 
:timer.sleep(:infinity) 

「kill」を送信してもVMは停止しないことに注意してください。これが単なるスクリプトの場合は、メッセージが「処理が完了していません」のときにをPracticeCaller.loop/1に追加すると、VMを直ちに停止できます。

+0

ああ、それは非常に便利です。ありがとうございました。 – Mascasc

関連する問題