所以,我开始玩Elixir,我想制作两个模块。一个会提示您输入消息,然后将消息发送到另一个程序,该程序将确认它收到消息,这将导致第一个程序打印出消息。
好吧,我遇到了问题。
发件人如下:
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
我的第一个问题是,当我启动发送器循环时,终端会提示我输入消息,但它不会打印收到的消息。
其次,当我输入“kill”时,终端会冻结,因为我不知道如何处理:kill响应。
有关解决这些问题的任何帮助吗?
答案 0 :(得分:3)
第一个问题是:
public class tblStudiosDTO
{
public string Standort { get; set; }
public string Name { get; set; }
public string Id { get; set; }
}
以及pid = :erlang.spawn(&PracticeServer.start/0)
再次调用PracticeServer.start/0
的事实。这意味着此处的spawn
并未引用正在运行pid
的流程,而是指生成PracticeServer.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
的惯用方法是在您希望进程死亡时不执行递归调用。这是一些重构的代码:
receive
请注意,即使发送“kill”,也不会暂停VM。如果这只是一个脚本,当消息为“Process Dead”时,您可以将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)
添加到:erlang.halt
以立即停止VM。