创建新的短代码Erlang时面临的问题

1l5u6lss  于 7个月前  发布在  Erlang
关注(0)|答案(1)|浏览(62)

我试图实现一个emoji服务器并为它编写代码。但是当我在终端测试它时,它显示超时错误。要检查代码,请检查alias函数:

-spec alias(Pid :: pid(), Short1 :: shortcode(), Short2 :: shortcode()) -> ok | {error, Reason :: term()}.
alias(Pid, Short1, Short2) when is_pid(Pid), is_list(Short1), is_list(Short2) ->
    Pid ! {alias, Short1, Short2},
    receive
        {ok, Short2} -> ok;
        {error, Reason} -> {error, Reason}
    after 1000 -> {error, timeout}
    end.

emoji_loop(State = #emoji_state{}) ->
    receive
        {alias, Short1, Short2} ->
            io:format("Received alias: Short1 = ~p, Short2 = ~p~n", [Short1, Short2]),
            case dict:find(Short1, State#emoji_state.shortcodes) of
                {ok, _} ->
                    case dict:find(Short2, State#emoji_state.aliases) of
                        {ok, _} -> emoji_loop(State);
                        error ->
                            NewAliases = dict:store(Short2, Short1, State#emoji_state.aliases),
                            emoji_loop(State#emoji_state{aliases = NewAliases})
                    end;
                error -> emoji_loop(State)
            end;
    end.

我已经添加了io:format来调试代码,似乎我的new_shortcode函数有问题,但我无法找到问题。
下面是我输入到终端的输入:

{ok, Pid} = emoji:start([{"happy", <<"😄">>}, {"sad", <<"😢">>}]).

然后接收到如下输出:

{ok,<0.92.0>}

然后又输入了另一个输入

emoji:new_shortcode(Pid, "dollar", <<"💵"/utf8>>).

收到了这样一条信息:

Received new_shortcode: Short = "dollar", Emo = <<240,159,146,181>>

超时错误{error,timeout}
如何才能完美地运行创建短代码功能?
谢谢你再次澄清,但我仍然在努力与停止功能。下面是循环中的stop函数的代码。

{stop, Pid} -> 
        if
            Pid =:= self() ->
                exit(Pid);
            true ->
                emoji_loop(State)
        end

在这个停止函数中,我需要在编写命令emoji:stop(Pid)时停止服务器。之后,服务器的表情符号命令将无法工作,并给予错误。这里是停止主函数,按照您的指示传递Pid。

-spec stop(Pid :: pid()) -> ok | {error, Reason :: term()}.
stop(Pid) when is_pid(Pid) ->
    Pid ! {stop, self()},
    receive
        ok -> ok;
        {error, Reason} -> {error, Reason}
    after 5000 ->
        {error, timeout}
    end.
xeufq47z

xeufq47z1#

查看new_shortcode/3函数,我们看到它向Pid发送了一条消息,然后期待一个响应,但是它在{error, timeout}上失败了,因为它从来没有得到那个响应:

new_shortcode(Pid, Short, Emo) when is_pid(Pid), is_binary(Emo), is_list(Short) ->
    Pid ! {new_shortcode, Short, Emo},
    receive
        {ok, Short} -> ok;
        {error, Reason} -> {error, Reason}
    after 1000 -> {error, timeout}
    end.

这里的Pid是运行emoji_loop/1函数的进程,它以元组的形式接收命令,并通过改变循环状态来执行命令。但是emoji_loop/1函数不做的是将消息发送回发送命令的进程,这就是为什么像new_shortcode/3这样的函数会超时等待回复。
要修复它,请将调用者的pid发送到emoji_loop/1,以便它可以回复。这意味着更改new_shortcode/1以将self()添加到它发送给emoji_loop/1的命令元组中:

new_shortcode(Pid, Short, Emo) when is_pid(Pid), is_binary(Emo), is_list(Short) ->
    Pid ! {new_shortcode, Short, Emo, self()},
    receive
        {ok, Short} -> ok;
        {error, Reason} -> {error, Reason}
    after 1000 -> {error, timeout}
    end.

然后,我们必须更改emoji_loop/1以将回复发送回调用者。例如,像这样更改new_shortcode的处理:

{new_shortcode, Short, Emo, Pid} ->
            io:format("Received new_shortcode: Short = ~p, Emo = ~p~n", [Short, Emo]),
            NewShortCodes = case dict:find(Short, State#emoji_state.shortcodes) of
                {ok, _} -> State#emoji_state.shortcodes;
                error ->
                    dict:store(Short, Emo, State#emoji_state.shortcodes)
            end,
            Pid ! {ok, Short},
            emoji_loop(State#emoji_state{shortcodes = NewShortCodes});

通过这个更改以及lookup的类似更改,我们可以看到它按预期工作:

3> {ok, Pid} = emoji:start([{"happy", <<"😄">>}, {"sad", <<"😢">>}]).
{ok,<0.138.0>}
4> emoji:new_shortcode(Pid, "dollar", <<"💵"/utf8>>).
Received new_shortcode: Short = "dollar", Emo = <<240,159,146,181>>
ok
5> emoji:lookup(Pid, "dollar").
Received lookup: Short = "dollar"
{ok,<<240,159,146,181>>}

我们必须对所有期望emoji_loop/1进程回复的命令函数进行类似的更改。
我强烈建议你考虑使用gen_server,而不是运行你自己的服务器,因为它可以轻松地处理你在这里尝试做的一切,也有助于错误处理和进程管理和清理。

  • 更新:这个问题被修改为添加了一个关于emoji:stop/1的具体问题,所以我更新了我的答案来解决它:*

emoji_loop/1中的原始stop处理程序只是退出:

stop ->
        exit(normal)

为了解决超时问题,您将其修改为:

{stop, Pid} -> 
        if
            Pid =:= self() ->
                exit(Pid);
            true ->
                emoji_loop(State)
        end

但这种变化有两个问题:

  1. Pid永远不会是self(),因为emoji_loop/1不会发送自己的消息,所以if的第一个子句永远不会发生。
    1.让emoji_loop/1像在true子句中那样递归地调用自己意味着循环进程保持运行,而不是按请求停止。
    要修复这些问题,您必须修复stop处理程序,就像上面修复new_shortcode处理程序一样:用命令传递调用者的pid,并让命令处理程序向调用者返回一个应答。如果我们回到原始的stop处理程序并进行这些更改,我们会得到:
{stop, Pid} ->
        Pid ! ok,
        exit(normal)

stop/1函数必须更改为使用命令发送其pid:

stop(Pid) when is_pid(Pid) ->
    Pid ! {stop, self()},
    receive
        ok -> ok;
        {error, Reason} -> {error, Reason}
    after 1000 -> {error, timeout}
    end.

我们可以测试stop/1来验证它是否真的停止了循环进程:

2> {ok, Pid} = emoji:start([{"happy", <<"😄">>}, {"sad", <<"😢">>}]).
{ok,<0.117.0>}
3> is_process_alive(Pid).
true
4> emoji:stop(Pid).
ok.
5> is_process_alive(Pid).
false

相关问题