1

我基本上是按照这个网站上的教程学习一些 Erlang:Designing a concurrent application我尝试使用以下命令运行下面的代码并在第 48 行出错。我确实关闭了我的防火墙以防万一问题,但没有运气。我在 windows xp SP3 上。

9> c(事件)。

{好的,事件}

10> f()。

好的

11> 事件:开始(“事件”,0)。

=错误报告==== 2013 年 2 月 9 日::15:05:07 === 进程 <0.61.0> 出错,退出值:{function_clause,[{event,time_to_go,[0],[{file ,"event.erl"},{line,48}]},{event,init,3,[{file,"event.erl"},{line,31}]}]}

<0.61.0>

12>

-module(event).
-export([start/2, start_link/2, cancel/1]).
-export([init/3, loop/1]).
-record(state, {server,
                name="",
                to_go=0}).

%%% Public interface
start(EventName, DateTime) ->
    spawn(?MODULE, init, [self(), EventName, DateTime]).

start_link(EventName, DateTime) ->
    spawn_link(?MODULE, init, [self(), EventName, DateTime]).

cancel(Pid) ->
    %% Monitor in case the process is already dead
    Ref = erlang:monitor(process, Pid),
    Pid ! {self(), Ref, cancel},
    receive
        {Ref, ok} ->
            erlang:demonitor(Ref, [flush]),
            ok;
        {'DOWN', Ref, process, Pid, _Reason} ->
            ok
    end.

%%% Event's innards
init(Server, EventName, DateTime) ->
    loop(#state{server=Server,
                name=EventName,
                to_go=time_to_go(DateTime)}).

%% Loop uses a list for times in order to go around the ~49 days limit
%% on timeouts.
loop(S = #state{server=Server, to_go=[T|Next]}) ->
    receive
        {Server, Ref, cancel} ->
            Server ! {Ref, ok}
    after T*1000 ->
        if Next =:= [] ->
            Server ! {done, S#state.name};
           Next =/= [] ->
            loop(S#state{to_go=Next})
        end
    end.

%%% private functions
time_to_go(TimeOut={{_,_,_}, {_,_,_}}) ->
    Now = calendar:local_time(),
    ToGo = calendar:datetime_to_gregorian_seconds(TimeOut) -
           calendar:datetime_to_gregorian_seconds(Now),
    Secs = if ToGo > 0  -> ToGo;
              ToGo =< 0 -> 0
           end,
    normalize(Secs).

%% Because Erlang is limited to about 49 days (49*24*60*60*1000) in
%% milliseconds, the following function is used
normalize(N) ->
    Limit = 49*24*60*60,
    [N rem Limit | lists:duplicate(N div Limit, Limit)].
4

2 回答 2

3

它纯粹在您的机器上本地运行,因此防火墙不会影响它。

问题是您在开始时给出的第二个参数event:start("Event",0).

错误原因:

{function_clause,[{event,time_to_go,[0],[{file,"event.erl"},{line,48}]},{event,init,3,[{file,"event.erl"},{line,31}]}]}

表示这是一个function_clause错误,这意味着函数定义中没有与参数匹配的子句。它还告诉您,是第event:time_to_go/148 行的函数失败了,并且使用参数调用了它0

如果您查看该函数time_to_go/,您将看到它希望其参数是 2 个元素的元组,其中每个元素是 3 个元素的元组:

time_to_go(TimeOut={{_,_,_}, {_,_,_}}) ->

这个论点的结构是{{Year,Month,Day},{Hour,Minute,Second}}。如果您向后遵循此参数,则从time_to_go/,init/3的参数调用的位置是 的第三个参数。现在差不多了。现在是进程产生的函数(和 start_link/2 init/3 start/2`.time_to_go/1DateTimeinit/3init/3start/2) and the 3rd argument tois the second argument to

因此,当您调用event:start("Event",0).它时,0这里将传递给time_to_go/1新进程中的调用函数。而且格式不对。你应该用类似的东西来调用它event:start("Event", {{2013,3,24},{17,53,62}}).

于 2013-02-10T02:46:11.573 回答
1

要为 rvirding 的答案添加背景,您会收到错误消息,因为据我所知,该示例一直有效,直到最终代码片段。该normalize函数首先使用,它处理问题。然后在上面问题中的示例之后的段落中,文字说:

它有效!事件模块的最后一件烦人的事情是我们必须输入以秒为单位的剩余时间。{{Year, Month, Day}, {Hour, Minute, Second}}如果我们可以使用标准格式,例如 Erlang 的 datetime ( ) ,那就更好了。只需添加以下函数,该函数将计算您计算机上的当前时间与您插入的延迟之间的差异:

下一个片段介绍了只需要一个日期/时间并将其更改为最后剩余时间的代码位。

我无法轻松链接到该文件的所有过渡版本,这就是为什么在这种情况下直接使用示例尝试链接文件并不容易。如果代码是一步一步地按照代码片段进行的,那么一切都应该可以正常工作。对困惑感到抱歉。

于 2013-04-16T13:36:12.043 回答