2016-02-12 5 views
5

मैं जानता हूँ कि मैं एक GenServer इसमैं जेनसेवर में वर्तमान प्रक्रिया में कॉल कैसे निष्पादित कर सकता हूं?

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

की तरह इस

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

फोन या की तरह लेकिन वहाँ पीआईडी ​​/ पंजीकृत नाम जानने के बिना GenServer.call मॉड्यूल के अंदर excute लिए एक रास्ता है कर सकते हैं? (यानी वहाँ

उत्तर

4

GenServer.call(__CURRENT_PROCESS__, request) की तरह कुछ है?) मुझे यकीन है कि जाने के लिए सबसे अच्छा तरीका है नहीं कर रहा हूँ लेकिन क्या आप देख रहे हैं Kernel.self/0

है

संपादित करें:

प्रति साशा की टिप्पणी कोड इस तरह दिखेगा:

GenServer.call(self, request) 

संपादित करें:

उत्कृष्ट पावेल Obrok द्वारा किए गए बिंदु के अनुसार, आप मौजूदा प्रक्रिया के लिए एक कॉल कभी नहीं करना चाहिए । आप इस fasion में यह करना चाहिए कि आप मौजूदा प्रक्रिया के लिए एक संदेश भेजना चाहते हैं तो:

GenServer.cast(self, request) 

एनबी यह बनाम बुला कास्टिंग है।

+0

ऑनोरियो की तरह, आप GenServer.call (स्वयं, अनुरोध) का उपयोग कर सकते हैं। इसमें देखें: http://elixir-lang.org/getting-started/processes.html या लिटिल एलिक्सीर और ओटीपी गाइड यदि आप प्रक्रियाओं और ओटीपी मंच पर गहराई से देखना चाहते हैं। –

+0

@Onorio यह एक अच्छा विचार क्यों नहीं है? – user3790827

+0

@ user3790827 मैंने यह नहीं कहा कि यह एक अच्छा विचार नहीं है। मैंने कहा कि मुझे यकीन नहीं है कि यह जाने का सबसे अच्छा तरीका है। यह कहना मुश्किल है कि मेरे पास आपके प्रश्न का लगभग कोई संदर्भ नहीं है। –

5

यह बस काम नहीं करेगा। GenServer.call बस दी गई प्रक्रिया को एक संदेश भेज रहा है और फिर वर्तमान प्रक्रिया को अवरुद्ध करते हुए एक और संदेश (उत्तर) की प्रतीक्षा कर रहा है। यदि आप self पर कोई संदेश भेजते हैं तो इस तरह की प्रक्रिया उस संदेश को संभालने के लिए स्वतंत्र नहीं होगी क्योंकि इसे उत्तर के लिए प्रतीक्षा कर दिया जाएगा। तो call हमेशा समय समाप्त होगा।

मुझे संदेह है कि आपको केवल उस कार्यक्षमता को निकालने के लिए जरूरी है जो आप किसी फ़ंक्शन में चाहते हैं और उसे सीधे कॉल करें। वैकल्पिक रूप से आप वर्तमान प्रक्रिया में cast भेज सकते हैं, प्रभावी ढंग से इसे "बाद में" करने के लिए कह रहे हैं।

+0

ओब्रोक मैं डेटा पुनर्प्राप्त करने के लिए कॉल का उपयोग कर रहा हूं। मुझे याद है कि मैंने कहीं पढ़ा है कि जब आप प्रतिक्रिया की आवश्यकता के बिना किसी प्रक्रिया को डेटा भेजते हैं और 'कॉल' करते हैं तो आप 'कास्ट' का उपयोग करने के लिए पुनः संयोजित होते हैं, जब आप वास्तव में दूसरी प्रक्रिया से डेटा पुनर्प्राप्त करना चाहते हैं। – user3790827

+0

ओब्रोक मैंने वास्तव में इसे एलीक्सिर हो रही प्रारंभ मार्गदर्शिका में पढ़ा है [यहां] (http://elixir-lang.org/getting-started/mix-otp/genserver.html#call-cast-or-info) – user3790827

+0

' कॉल' वास्तव में डेटा पुनर्प्राप्त करने के लिए उपयोग किया जाता है लेकिन वर्तमान प्रक्रिया से नहीं। यदि आप 'जेनसेवर' में हैं, तो संभावना है कि आप 'हैंडल_ल'', हैंडल_कास्ट या 'हैंडल_इनोफो' कॉलबैक में हैं - इन सभी में आपके पास 'जेनसेवर' की स्थिति तक पहुंच है, इसलिए वहां नहीं होना चाहिए इसके अतिरिक्त उसी प्रक्रिया से अनुरोध करने का कारण। –

1

आपकी टिप्पणी से मैं जो समझता हूं उससे आप GenServer प्रक्रिया के भीतर call बनाने के बजाय अपने GenServer के लिए एक सार्वजनिक एपीआई फ़ंक्शन लिखने की कोशिश कर रहे हैं। AFAIK पीआईडी ​​को जानने के बिना ऐसा करने का कोई तरीका नहीं है। हालांकि GenServers के लिए, जिसमें से आप केवल एक उदाहरण बनाते हैं, ऐसे मामले के लिए एक मुहावरे मौजूद है: आप इसे लागू करने वाले मॉड्यूल के नाम के साथ अपने GenServer का एकमात्र उदाहरण नाम दें। इस का उपयोग कर आसानी से किया जा सकता है __MODULE__ मैक्रो:

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

और फिर अपने एपीआई कार्यों में आप सिर्फ पीआईडी ​​के स्थान पर __MODULE__ का उपयोग करें:

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

यह अच्छा संपत्ति है कि __MODULE__ हमेशा प्रतिबिंबित करेगा है संलग्न मॉड्यूल का सही नाम, भले ही आप इसका नाम बदल दें।

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 फ़ाइल की तरह करने के लिए जोड़ सकते हैं:

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

एक तरफ ध्यान दें पर, कभी नहीं, कभी handle_call/3 के भीतर से GenServer.call/3 कहते हैं। यह समय-समय पर होगा और आपके अन्य GenServer.call एस पर एक डॉस करेगा। handle_call/3 उस समय एक संदेश संभालता है।

संबंधित मुद्दे