我有这个与我合作的gen_server:
-module(user_info_provider).
-export([start_link/0, stop/0]).
-export([init/1, terminate/2, handle_info/2, handle_call/3, handle_cast/2,
code_change/3]).
-export([request_user_info/2]).
-behaviour(gen_server).
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
stop() ->
gen_server:cast(?MODULE, stop).
request_user_info(From,UserId) ->
gen_server:cast(?MODULE, {request_user_info, From, UserId}).
%% Callback Functions
init(_) ->
process_flag(trap_exit, true),
io:format("I am ~w ~n", [self()]),
{ok, null}.
%% @doc terminate
terminate(Reason, _LoopData) ->
io:format("Terminating by ~w~n",[Reason]),
{ok, null}.
handle_cast({request_user_info,From,UserId}, LoopData) ->
{noreply, LoopData};
handle_cast(stop, LoopData) ->
{stop, normal, LoopData}.
handle_info(_Info, State) ->
{ok, State}.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
handle_call(_,_From,LoopData) ->
{ok,ok,LoopData}.
Run Code Online (Sandbox Code Playgroud)
问题是,正如我接下来所展示的那样,如果我从cli中执行它就像 …
我正在从Erlang Programming一书中练习练习12-2.我有一个模块db_server_otp,它实现了一个OTP gen_server行为.作为一个独立的模块,我测试了它,它按预期工作.我现在必须为它添加一个主管.根据本章中的示例,我创建了一个模块db_server_sup,如下所示:
-module(db_server_sup).
-export([start/0,init/1]).
-behavior(supervisor).
start() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
init(_Arguments) ->
DbServerOtp = {db_server_otp, %% Id
{db_server_otp, start, []}, %% child process
permanent, %% restart
30000, %% shutdown (ms)
worker, %% type
{db_server_otp}}, %% required modules
{ok,
{{one_for_all, %% terminate all children and restart
5, %% max of n restarts in MaxSeconds
3600}, %% MaxSeconds (s)
[DbServerOtp]}}. %% child process list
Run Code Online (Sandbox Code Playgroud)
两个模块都位于同一个目录中,我用.beam文件编译这两个模块都在我启动erlang shell的同一个工作目录中.但是,使用erlang shell,我无法启动主管.
Erlang R13B03 (erts-5.7.4) [source] [64-bit] [smp:8:2] [rq:8] [async-threads:0] [hipe] …Run Code Online (Sandbox Code Playgroud) 我有一个Erlang应用程序,它有点太资源不足以留在一个节点上.我正在使gen_servers从一个进程转移到另一个进程 - 结果相对容易.我处于最后一个障碍:获取创建这些gen_servers的工厂进程以在远程节点而不是本地节点上生成它们.start_link的默认行为显然只在本地启动,但我没有看到任何更改它的选项.
似乎我必须要有创造力的解决方案,并想看看是否有人已经实现了这样的事情,并取得了任何成功.IOW,推荐的解决方案是什么?
编辑
我正在查看通过调用触发的调用链:
gen_server:start_link(?Module, Args, [])
Run Code Online (Sandbox Code Playgroud)
gen_server:START_LINK/3:
start_link(Mod, Args, Options) ->
gen:start(?MODULE, link, Mod, Args, Options).
Run Code Online (Sandbox Code Playgroud)
创:启动/ 5:
start(GenMod, LinkP, Mod, Args, Options) ->
do_spawn(GenMod, LinkP, Mod, Args, Options).
Run Code Online (Sandbox Code Playgroud)
创:do_spawn/5:
do_spawn(GenMod, link, Mod, Args, Options) ->
Time = timeout(Options),
proc_lib:start_link(?MODULE, init_it,
[GenMod, self(), self(), Mod, Args, Options],
Time,
spawn_opts(Options));
Run Code Online (Sandbox Code Playgroud)
proc_lib:START_LINK/5:
start_link(M,F,A,Timeout,SpawnOpts) when is_atom(M), is_atom(F), is_list(A) ->
Pid = ?MODULE:spawn_opt(M, F, A, ensure_link(SpawnOpts)),
sync_wait(Pid, Timeout).
Run Code Online (Sandbox Code Playgroud)
这最终让我们感到有趣.有一个匹配的spawn_opt/4:
spawn_opt(M, F, A, Opts) when is_atom(M), is_atom(F), is_list(A) ->
...
... …Run Code Online (Sandbox Code Playgroud) 有人告诉我,simple_one_for_one对聊天应用程序非常有用,因为每个聊天客户端都是一个服务器进程(gen_server).这是正确的吗?
我想知道为什么我们需要它?为什么不创建一个中心服务器(gen_server)来处理所有聊天客户端通信?因为聊天客户端的数量可能非常大,所以只有一台服务器无法快速处理,导致系统速度变慢?
我认为创建像simple_one_for_one这样的服务器太多可能会占用过多的系统资源.我是一个新的OTP人,所以我真的需要解释这一点.
当我尝试使用 .shell 通过 shell 运行我的程序时,出现以下错误erlang.mk:
=INFO REPORT==== 5-May-2016::05:47:57 ===
application: rad
exited: {bad_return,
{{rad_app,start,[normal,[]]},
{'EXIT',
{noproc,{gen_server,call,[rad_config,{lookup,port}]}}}}}
type: permanent
Eshell V6.4 (abort with ^G)
(rad@127.0.0.1)1> {"Kernel pid terminated",application_controller,"{application_start_failure,rad,{bad_return,{{rad_app,start,[normal,[]]},{'EXIT',{noproc,{gen_server,call,[rad_config,{lookup,port}]}}}}}}"}
Kernel pid terminated (application_controller) ({application_start_failure,rad,{bad_return,{{rad_app,start,[normal,[]]},{'EXIT',{noproc,{gen_server,call,[radheart: Thu May 5 05:47:58 2016: _coErlang is crashing .. (waiting for crash dump file)nf
ig,{lookup,porheart: Thu May 5 05:47:58 2016: tWould reboot. Terminating.}
]}}}}}})
make: *** [run] Error 1
Run Code Online (Sandbox Code Playgroud)
rad.app.src
{application, rad,
[
{description, "Awesome server written in Erlang"},
{vsn, "0.0.1"},
{registered, [rad_sup, rad_config]},
{modules, []}, …Run Code Online (Sandbox Code Playgroud) 我正在尝试在回复之前对handle_call/3进行递归调用.但似乎不可能,因为timeout抛出了退出异常.您可以在下面看到代码和错误.
代码:
-module(test).
-behavior(gen_server).
%% API
-export([start_link/0,init/1,handle_info/2,first_call/1,second_call/1, handle_call/3, terminate/2]).
-record(state, {whatever}).
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
init(_Args) ->
{ok, #state{}}.
handle_info(Data, State) ->
{noreply, State}.
% synchronous messages
handle_call(_Request, _From, State) ->
case _Request of
first_call ->
{reply, data1, State};
second_call ->
{reply, {data2, first_call(self())}, State}
end.
first_call(Pid) ->
gen_server:call(Pid, first_call).
second_call(Pid) ->
gen_server:call(Pid, second_call).
terminate(_Reason, _State) ->
ok.
Run Code Online (Sandbox Code Playgroud)
错误:
2> {_, PID} = test:start_link().
{ok,<0.64.0>}
3> test:second_call(PID).
** exception exit: {timeout,{gen_server,call,[<0.64.0>,second_call]}}
in function gen_server:call/2 (gen_server.erl, …Run Code Online (Sandbox Code Playgroud) 我有一个实现单个项目功能的GenServer,例如:
def handle_call({:sync, id}, _from, state) do
## update data
{:reply, data, sync}
end
Run Code Online (Sandbox Code Playgroud)
现在我想为多个id处理这个功能,例如:
def handle_call({:sync_all, ids}, _from, state) do
## call sync for each id
data = Enum.map(ids, fn(id) ->
GenServer.call(self(), {:sync, id})
end)
## Further reduce down data to stats
{:reply, data, sync}
end
Run Code Online (Sandbox Code Playgroud)
然而,这并不能告诉我该过程试图调用自己.
我认为这必然是由于阻塞性质call.如果我cast在sync_all版本中使用,则会发生相同的情况.
所以我的问题是:如何GenServer从一个handle_call或一个handle_cast函数中调用其他任务?
我正在实施一个GenServer,我很困惑.
我知道handle_cast是异步的,这意味着调用者不等待回复,我们返回一个这样的元组:{:noreply, new_state}.
我注意到我们也可以从中返回相同的元组handle_call.这是否意味着如果我有一个handle_call返回{:noreply, new_state},它不会返回任何东西但会同步?调用者的流程将等待GenServer.call命令,然后在handle_call函数完成后继续?
我正在尝试创建一个动态主管来启动子进程。我使用三个模块来做到这一点,一个是主模块,第二个是动态主管,第三个是 genserver。我没有收到任何错误,但我看不到任何正在运行的子进程。
这是我的代码。第一个是具有主要方法的模块
defmodule Simulator do
def main(args) do
{:ok, super_pid} = PersonManager.start_link(args)
num_of_persons = 1
start_persons(num_of_persons)
IO.inspect PersonManager.count_children, label: "The Persons started in main method are"
end
def start_persons(num_of_persons) when num_of_persons >=1 do
PersonManager.add_node(private_key, public_key, 0)
start_persons(num_of_persons-1)
end
# num_of_persons == 0 case handled
end
Run Code Online (Sandbox Code Playgroud)
以下是动态Supervisor
defmodule PersonManager do
use DynamicSupervisor
def start_link(args) do
DynamicSupervisor.start_link(__MODULE__, :ok, name: __MODULE__)
end
def add_node(private_key, public_key, num_of_coins) do
# The code flow does come here, used inspect to check
child_spec = {Person, {private_key, …Run Code Online (Sandbox Code Playgroud) 我正在努力完成一项简单的任务,但我遇到了很大的困难.
请假设我有一个GenServer,其中一个回调如下:
@impl true
def handle_call(:state, _, state) do
# Something that would require 10 seconds
newState = do_job()
{:reply, newState, newState}
end
Run Code Online (Sandbox Code Playgroud)
如果我是对的,GenServer.call(:server, :state)从客户端调用会阻塞服务器10秒钟,然后新状态将返回给客户端.
好.我希望服务器在不被阻止的情况下处理此任务.我使用任务尝试过,但Task.await/2和Task.yield/2阻塞服务器.
我希望服务器不要阻塞,并在那10秒后,在客户端终端上接收结果.这怎么可能?
gen-server ×10
erlang ×7
elixir ×4
erlang-otp ×4
distributed ×1
function ×1
linux ×1
nodes ×1
nonblocking ×1
recursion ×1