【问题标题】:Call a function after a time interval, each time with updated arguments在一个时间间隔后调用一个函数,每次都使用更新的参数
【发布时间】:2019-09-13 03:35:47
【问题描述】:

我有一个数据包,如果它包含一个特定的标签(比如 testtag),那么我需要等待一段时间才能使用数据包标签中的参数值(比如 valuetag)实现一个特定的功能(比如 testfunction),但是如果在此期间超时该数据包再次出现但具有不同的值标签,然后使用更新的值实现测试功能。 如何实现?

【问题讨论】:

    标签: erlang


    【解决方案1】:

    通常,它需要显示您到目前为止尝试过的内容。但我发现这个问题很酷,所以我建议你一个解决方案。 cmets很少,但我认为它相对容易阅读。 (我让你找到如何从数据包中提取函数测试名称和参数并调用用户接口)

    -module (test_tag).
    
    
    -export ([start/0,activate/3,modify/2,remove/1,stop/0]).
    
    -export ([test_server/1,proc_server/3]).
    
    -export ([test1/2,test2/3]).
    
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % User Interface
    
    % start the test with an empty map of pending test process
    start() ->
        Pid = spawn(?MODULE, test_server, [#{}]),
        register(test_server, Pid).
    
    activate(TestName,ParamList,Timeout) when 
        is_atom(TestName), is_list(ParamList), is_number(Timeout) ->
        test_server ! {activate,TestName,ParamList,Timeout}.
    
    modify(TestName,ParamList) when is_atom(TestName), is_list(ParamList) ->
        test_server ! {modify,TestName,ParamList}.
    
    remove(TestName) when is_atom(TestName) ->
        test_server ! {remove,TestName}.
    
    stop() ->
        test_server ! stop.
    
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % internal interface
    
    completed(TestName) ->
        test_server ! {completed,TestName,self()}.
    
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % Sever loop (receive user request and organize the job)
    
    % test_server(stop | map())
    test_server(stop) ->
        io:format("stopped by user~n");
    test_server(Pending) ->
        NewPending = receive 
            {activate,TestName,ParamList,Timeout} ->
                activate_test(TestName,ParamList,Timeout,Pending);
            {modify,TestName,ParamList} ->
                modify_test(TestName,ParamList,Pending);
            {remove,TestName} ->
                remove_test(TestName,Pending);
            {completed,TestName,Pid} ->
                test_complete(TestName,Pid,Pending);
            stop -> stop_test(Pending)
        end,
        test_server(NewPending).
    
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % helper functions (in charge to do the server job)
    
    activate_test(TestName,ParamList,Timeout,Pending) ->
        case maps:is_key(TestName, Pending) of 
            true ->
                io:format("test ~p already started~n",[TestName]),
                Pending; %do nothing
            false ->
                Pid = spawn(?MODULE,proc_server,[TestName,ParamList,Timeout]),
                maps:put(TestName, Pid, Pending)
        end.
    
    modify_test(TestName,ParamList,Pending) ->
        case maps:get(TestName, Pending,undefined) of 
            undefined ->
                io:format("test ~p not started~n",[TestName]);
            Pid ->
                Pid ! {new_param,TestName,ParamList}
        end,
        Pending. % Map unchanged.
    
    remove_test(TestName,Pending) ->
        case maps:get(TestName, Pending,undefined) of 
            undefined ->
                io:format("test ~p not started~n",[TestName]),
                Pending;
            Pid ->
                Pid ! {stop,TestName},
                maps:remove(TestName, Pending)
        end.
    
    test_complete(TestName,Pid,Pending) ->
        case maps:get(TestName, Pending,undefined) of 
            undefined ->
                Pending; % already removed, presumably by user
            Pid ->
                Pid ! {stop,TestName},
                maps:remove(TestName, Pending)
        end.
    
    
    stop_test(Pending) ->
        maps:map(fun(TestName,Pid) -> Pid ! {stop,TestName} end, Pending),
        stop. % return stop to end the test server loop
    
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    
    % init the process in charge to execute a test after a while
    proc_server(TestName,ParamList,Timeout) ->
        timer:send_after(Timeout, self(), {execute,TestName}),
        proc_server(TestName,ParamList).
    
    % listening loop
    proc_server(TestName,ParamList) ->
        receive 
            {execute,TestName} -> 
                catch(apply(?MODULE,TestName, ParamList)),
                completed(TestName);
            {new_param,TestName,NewParamList} ->
                proc_server(TestName,NewParamList);
            {stop,TestName} ->
                io:format("test ~p stopped\n",[TestName]),
                stop
        end.
    
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % User tests
    
    test1(Param1,Param2) ->
        io:format("executing test1 with params ~p and ~p ~n",[Param1,Param2]).
    
    test2(Param1,Param2,Param3) ->
        io:format("executing test2 with params ~p, ~p and ~p~n",[Param1,Param2,Param3]).
    

    在shell中执行

    1> c(test_tag).                                   
    {ok,test_tag}
     test_tag:start().                              
    true
    2> test_tag:activate(test1,[hello,"hello"],20000).
    {activate,test1,[hello,"hello"],20000}
    3> test_tag:modify(test1,[hello,"hello guys"]).   
    {modify,test1,[hello,"hello guys"]}
    executing test1 with params hello and "hello guys" 
    4> test_tag:activate(test1,[hello,"hello"],20000).
    {activate,test1,[hello,"hello"],20000}
    5> test_tag:activate(test1,[hello,"hello"],20000).
    test test1 already started
    {activate,test1,[hello,"hello"],20000}
    executing test1 with params hello and "hello"       
    6> test_tag:remove(test1).                        
    test test1 not started
    {remove,test1}
    7> test_tag:activate(test1,[hello,"hello"],20000).
    {activate,test1,[hello,"hello"],20000}
    8> test_tag:remove(test1).                        
    test test1 stopped
    {remove,test1}
    9> test_tag:activate(test2,[hello,"hello",12],20).   
    {activate,test2,[hello,"hello",12],20}
    executing test2 with params hello, "hello" and 12
    10> test_tag:activate(test2,[hello,"hello"],20).   
    {activate,test2,[hello,"hello"],20}
    11> test_tag:activate(test2,[hello,"hello"],20000).
    {activate,test2,[hello,"hello"],20000}
    12> test_tag:activate(test2,[hello,"hello"],20000).
    test test2 already started
    {activate,test2,[hello,"hello"],20000}
    13> test_tag:remove(test2).                        
    test test2 stopped
    {remove,test2}
    14> test_tag:activate(test3,[hello,"hello"],20000).
    {activate,test3,[hello,"hello"],20000}
    15> %wait 20 sec
    15> test_tag:remove(test3).                        
    test test3 not started
    {remove,test3}
    16> 
    

    【讨论】:

    • 我对erlang特别陌生,请您解释一下为什么在使用new_param调用时,超时仍然只发生在原始结束时间
    • 因为我认为这是你的意图。如果要重新启动一个完整的超时,则有必要在 modify_test 函数中使用函数 timer:cancel(Tref) 取消当前超时并重新启动一个新超时。为此,proc_server循环需要存储timer:send_after/3返回的Tref,还需要存储超时参数(或添加到修改接口)。
    猜你喜欢
    • 2019-04-29
    • 2019-02-16
    • 2021-08-07
    • 1970-01-01
    • 2018-09-13
    • 2018-01-18
    • 2023-03-12
    • 2017-03-13
    • 2018-12-13
    相关资源
    最近更新 更多