2016-02-12 4 views
5

私はこのGenServerで現在のプロセスへの呼び出しを実行するにはどうすればよいですか?

GenServer.call(pid, request) 
# using a pid 

またはこの

GenServer.call(registered_name, request) 
# if I registered the process with a name 

などのようGenServerを呼び出すことができます。しかし、PID /登録名を知らなくても、モジュール内部のGenServer.callをexcuteする方法はありますか?(つまり、知っていますGenServer.call(__CURRENT_PROCESS__, request)のようなものがあるのでしょうか?)

答えて

4

私はそれが行くための最善の方法だか分からないけど、あなたが探しているのはKernel.self/0

です

EDIT:

コードは次のようになります

パーサーシャさんのコメント:

GenServer.call(self, request) 

EDIT:パヴェルObrokによって作られた優れたポイント毎の

、あなたは現在のプロセスへの呼び出しを行うべきではありません。あなたが現在のプロセスにメッセージを送信する必要がある場合は、この流行っでそれを行う必要があります。それは、呼び出し対キャストだ

GenServer.cast(self, request) 

NB。

+0

Onorio氏のように、GenServer.call(self、request)を使用することができます。プロセスとOTPプラットフォームの詳細を知りたい場合は、 http://elixir-lang.org/getting-started/processes.html またはLittle Elixir and OTP Guideを参照してください。 –

+0

@Onorioなぜそれは良い考えではありませんか? – user3790827

+0

@ user3790827いい考えではないとは言いませんでした。私はそれが最善の方法だとはっきりしないと言いました。あなたの質問に文脈がほとんどないことを考えると、本当に難しいです。 –

5

これは単に機能しません。 A GenServer.callは、指定されたプロセスにメッセージを送信し、現在のプロセスをブロックする別のメッセージ(応答)を待っているだけです。 selfにメッセージを送信すると、返信を待つことがブロックされるため、プロセスはそのメッセージを自由に処理できません。したがって、callは常にタイムアウトします。

私が必要と思うのは、機能に必要な機能を抽出し、直接呼び出すことです。あるいは、castを現在のプロセスに送信して、「後で」何かを行うように効果的に伝えることができます。

+0

Obrok私はデータを取得するために呼び出しを使用しています。私は、あなたが実際に他のプロセスからデータを取得したいときには、レスポンスを必要とせずにプロセスにデータを送るときには 'cast'を使用し、実際には' call'を使うことが推奨されています。 – user3790827

+0

Obrok私は実際にエリクシル入門ガイド[こちら](http://elixir-lang.org/getting-started/mix-otp/genserver.html#call-cast-or-info) – user3790827

+0

'現在のプロセスからではなくデータを検索するために実際に使用されます。あなたが 'GenServer'を使っているなら、あなたは' handle_call'、 'handle_cast'、または' handle_info'コールバックにいる可能性があります - これらの全てにおいて 'GenServer'の状態にアクセスできるので、同じプロセスから追加要求する理由。 –

1

ご回答いただいた内容から、GenServerのプロセスからcallを作成する代わりに、お客様のGenServerの公開API関数を作成しようとしています。 AFAIKでは、PIDを知らなくてもそれを行う方法はありません。しかし、GenServersのうち、1つのインスタンスのみを作成する場合、そのような場合のイディオムが存在します。GenServerの唯一のインスタンスにそれを実装するモジュールの名前を付けます。これは、マクロ__MODULE__を使用して簡単に行うことができます:あなただけのPIDの代わりに__MODULE__を使用して、あなたのAPI関数で

def start_link do 
    GenServer.start_link(__MODULE__, nil, name: __MODULE__) 
end 

そして:

def api_function do 
    GenServer.call(__MODULE__, :api_function) 
end 

これは__MODULE__が常に反映されるという素晴らしい特性を持っています名前を変更しても、そのモジュールの正しい名前。

1

です。あなたが唯一のノードごとに1つのGenServerプロセスを開始する場合は、好きなことを呼び出すことができます。

@doc """ 
If you want to call the server only from the current module. 
""" 
def local_call(message) do 
    GenServer.call(__MODULE__, message) 
end 

または

@doc """ 
If you want to call the server from another node on the network. 
""" 
def remote_call(message, server \\ nil) do 
    server = if server == nil, do: node(), else: server 
    GenServer.call({__MODULE__, server}, message) 
end 

を使用すると、同じモジュールからのいくつかのプロセスを持っている場合ならば、あなたは、例えば、(余分な識別子を必要としますオンデマンドでGenServerを生成するスーパーバイザー戦略:simple_one_for_oneがあります。私が使用することをお勧めしますというようなものについては

  • :gproc名プロセスへ。
  • :etsプロセスを識別するための追加情報が必要な場合は、

:gprocは、GenServerで動作します。通常は、アトムを登録名として使用してプロセスの名前を付けます。 :gprocでは、任意のターム、つまりタプルを使用してプロセスに名前を付けることができます。

私の関数呼び出しでは、{:id, id :: term}のような私のサーバーの複雑な識別子があります。ここで、idは文字列にすることができます。私は私のGenServerのように起動することができます:

defmodule MyServer do 
    use GenServer 

    def start_link(id) do 
    name = {:n, :l, {:id, id}} 
    GenServer.start_link(__MODULE__, %{}, name: {:via, :gproc, name}) 
    end 
    (...) 
end 

をそして私は、例えば、文字列、前に言ったように、原子よりも別の何かで私のプロセスを調べます。だから私は次のように自分のサーバーを起動した場合:

MyServer.start_link("My Random Hash") 

そして、私はのような機能を持っている:あなたの命名プロセスである場合

MyServer.f("My Random Hash", {:message, "Hello"}) 

:あなたが好きなプロセスを呼び出すためにそれを使用することができます

def f(id, message) do 
    improved_call(id, message) 
end 

defp improved_call(id, message, timeout \\ 5000) do 
    name = {:n, :l, {:id, id}} 
    case :gproc.where(name) do 
    undefined -> :error 
    pid -> GenServer.call(pid, message, timeout) 
end 

より複雑な場合は、:etsを使用してより複雑な状態を格納できます。

あなたが:gprocを使用したい場合は、次のようにあなたのmix.exsファイルに追加することができます。決して、これまでhandle_call/3内からGenServer.call/3を呼び出し、サイドノートでは

(...) 
defp deps do 
    [{:gproc, github: "uwiger/gproc"}] 
end 
(...) 

。それはあなたの他のGenServer.callでタイムアウトし、DOSを行います。 handle_call/3は、その時点で1つのメッセージを処理します。