我有一个实现单个项目功能的GenServer,例如:
def handle_call({:sync, id}, _from, state) do
## update data
{:reply, data, sync}
end
现在我想为多个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
然而,这并不能告诉我该过程试图调用自己。
我认为这必须归因于call
的阻止性质。如果我在cast
版本中使用sync_all
,则会发生同样的情况。
所以我的问题是:如何在GenServer
或handle_call
函数中调用其他handle_cast
个任务?
答案 0 :(得分:7)
在这种情况下,您通常会将共同逻辑提取到单独的函数中:
def handle_call({:sync, id}, _from, state) do
{data, state} = do_sync(id, state)
{:reply, data, state}
end
def handle_call({:sync_all, ids}, _from, state) do
{data, state} = Enum.map_reduce(ids, state, &do_sync/2)
{:reply, data, state}
end
defp do_sync(id, state) do
# do something
{data, new_state}
end
答案 1 :(得分:1)
对同一进程进行GenServer调用没有多大意义。一个进程一次处理一条消息。通话将等待回答。但是,在完成当前消息之前,该过程无法应答。您拥有的代码将等待答案超时,因为进程永远不会完成处理当前消息,因此永远不会处理随呼叫发送的消息。
通常,您使用强制转换和调用来定义其他进程的接口,以将消息发送到进程。您可以将实际数据转换建模为纯函数,然后根据需要从两个处理函数中调用这些函数。