Elixir 1.7

Task




elixir

Task

स्पैनिंग और प्रतीक्षारत कार्यों के लिए सुविधा।

कार्य वे प्रक्रियाएं होती हैं जो जीवन भर में एक विशेष क्रिया को निष्पादित करने के लिए होती हैं, अक्सर अन्य प्रक्रियाओं के साथ बहुत कम या कोई संचार नहीं होता। कार्यों के लिए सबसे आम उपयोग मामला अनुक्रमिक कोड को समवर्ती रूप से मान गणना करके समवर्ती कोड में परिवर्तित करना है:

task = Task.async(fn -> do_some_work() end)
res  = do_some_other_work()
res + Task.await(task)

ऊपर दिए गए उदाहरण में दिखाए गए अनुसार async साथ काम किए गए कार्य उनकी कॉलर प्रक्रिया (और केवल उनके कॉलर) द्वारा प्रतीक्षा की जा सकती है। उन्हें एक प्रक्रिया को लागू करने के द्वारा कार्यान्वित किया जाता है जो कॉल करने वाले को एक संदेश देता है एक बार दिए गए अभिकलन के प्रदर्शन के बाद।

async/1 और await/2 , कार्यों को एक पर्यवेक्षण वृक्ष के हिस्से के रूप में भी शुरू किया जा सकता है और गतिशील रूप से दूरस्थ नोड्स पर देखा जा सकता है। हम अगले तीन परिदृश्यों का पता लगाएंगे।

async और प्रतीक्षा करें

कार्यों के सामान्य उपयोगों में से एक अनुक्रमिक कोड को समसामयिक रखते हुए Task.async/1 के साथ समवर्ती कोड में परिवर्तित करना है। जब आह्वान किया जाता है, तो कॉलर द्वारा एक नई प्रक्रिया बनाई जाएगी, लिंक की जाएगी और निगरानी की जाएगी। टास्क एक्शन खत्म होने के बाद, परिणाम के साथ कॉल करने वाले को एक संदेश भेजा जाएगा।

Task.await/2 का उपयोग कार्य द्वारा भेजे गए संदेश को पढ़ने के लिए किया जाता है।

async का उपयोग करते समय विचार करने के लिए दो महत्वपूर्ण बातें हैं:

  1. यदि आप async कार्यों का उपयोग कर रहे हैं, तो आपको एक उत्तर की प्रतीक्षा करनी चाहिए क्योंकि वे हमेशा भेजे जाते हैं। यदि आप उत्तर की उम्मीद नहीं कर रहे हैं, तो नीचे Task.start_link/1 का उपयोग करने पर विचार करें।

  2. async कार्य कॉलर और स्पैन्ड प्रक्रिया को लिंक करता है। इसका मतलब है कि, यदि कॉलर क्रैश हो जाता है, तो कार्य भी दुर्घटनाग्रस्त हो जाएगा और इसके विपरीत। यह उद्देश्य पर है: यदि परिणाम प्राप्त करने के लिए प्रक्रिया अब मौजूद नहीं है, तो अभिकलन पूरा करने का कोई उद्देश्य नहीं है।

    यदि यह वांछित नहीं है, तो Task.start/1 उपयोग करें या टास्क के तहत कार्य शुरू करने पर विचार करें। async_nolink या start_child का उपयोग करके start_child

Task.yield/2 await/2 करने के लिए एक विकल्प है await/2 जहां कॉलर अस्थायी रूप से ब्लॉक करेगा, जब तक कि कार्य उत्तर नहीं देता या क्रैश नहीं होता। यदि परिणाम टाइमआउट के भीतर नहीं आता है, तो इसे बाद में फिर से बुलाया जा सकता है। यह कई बार किसी कार्य के परिणाम की जाँच करने की अनुमति देता है। यदि कोई उत्तर वांछित समय के भीतर नहीं आता है, तो Task.shutdown/2 का उपयोग कार्य को रोकने के लिए किया जा सकता है।

पर्यवेक्षण कार्य

एक पर्यवेक्षक के तहत किसी कार्य को स्पॉन करना भी संभव है। Task मॉड्यूल child_spec/1 फ़ंक्शन को लागू करता है, जो इसे चलाने के लिए एक फ़ंक्शन के साथ एक ट्यूपल को पारित करके सीधे पर्यवेक्षक के तहत शुरू करने की अनुमति देता है:

Supervisor.start_link([
  {Task, fn -> ... some function ... end}
])

हालाँकि, यदि आप किसी विशिष्ट मॉड्यूल, फ़ंक्शन और तर्कों को लागू करना चाहते हैं, या कार्य प्रक्रिया को एक नाम देना चाहते हैं, तो आपको कार्य को अपने मॉड्यूल में परिभाषित करना होगा:

defmodule MyTask do
  use Task

  def start_link(arg) do
    Task.start_link(__MODULE__, :run, [arg])
  end

  def run(arg) do
    # ...
  end
end

और फिर इसे पर्यवेक्षक के पास भेजना:

Supervisor.start_link([
  {MyTask, arg}
])

चूंकि इन कार्यों की देखरेख की जाती है और कॉलर से सीधे नहीं जुड़े होते हैं, इसलिए उनका इंतजार नहीं किया जा सकता है। नोट start_link/1 , async/1 विपरीत, {:ok, pid} (जो पर्यवेक्षकों द्वारा अपेक्षित परिणाम है) लौटाता है।

नोट use Task child_spec/1 फ़ंक्शन को परिभाषित करता है, जिससे परिभाषित मॉड्यूल को पर्यवेक्षण के पेड़ के नीचे रखा जा सकता है। उत्पन्न child_spec/1 को निम्नलिखित विकल्पों के साथ अनुकूलित किया जा सकता है:

  • :id - बाल विनिर्देश पहचानकर्ता, वर्तमान मॉड्यूल में चूक
  • :start - बच्चे की प्रक्रिया कैसे शुरू करें ( __MODULE__.start_link/1 को कॉल करने के लिए चूक __MODULE__.start_link/1 )
  • :restart - जब बच्चे को फिर से शुरू किया जाना चाहिए, चूक करना :temporary
  • :shutdown - बच्चे को कैसे बंद किया जाए

GenServer , Agent और Supervisor विपरीत, एक टास्क में एक डिफ़ॉल्ट :restart होता है :temporary । इसका अर्थ यह है कि क्रैश होने पर भी कार्य को पुनः आरंभ नहीं किया जाएगा। यदि आप गैर-सफल निकास के लिए कार्य को फिर से शुरू करने की इच्छा रखते हैं, तो करें:

use Task, restart: :transient

यदि आप चाहते हैं कि कार्य हमेशा पुनरारंभ हो:

use Task, restart: :permanent

अधिक जानकारी के लिए Supervisor डॉक्स देखें।

गतिशील रूप से पर्यवेक्षण कार्यों

Task.Supervisor मॉड्यूल डेवलपर्स को कई पर्यवेक्षित कार्यों को गतिशील रूप से बनाने की अनुमति देता है।

एक छोटा उदाहरण है:

{:ok, pid} = Task.Supervisor.start_link()
task = Task.Supervisor.async(pid, fn ->
  # Do something
end)
Task.await(task)

हालाँकि, अधिकांश मामलों में, आप कार्य पर्यवेक्षक को अपने पर्यवेक्षण ट्री में जोड़ना चाहते हैं:

Supervisor.start_link([
  {Task.Supervisor, name: MyApp.TaskSupervisor}
])

अब आप गतिशील रूप से पर्यवेक्षित कार्यों को शुरू कर सकते हैं:

Task.Supervisor.start_child(MyApp.TaskSupervisor, fn ->
  # Do something
end)

या यहां तक ​​कि async / प्रतीक्षा पैटर्न का उपयोग करें:

Task.Supervisor.async(MyApp.TaskSupervisor, fn ->
  # Do something
end) |> Task.await()

अंत में, अन्य समर्थित कार्यों के लिए Task.Supervisor जाँच करें।

वितरित कार्य

चूंकि अमृत एक कार्य पर्यवेक्षक प्रदान करता है, इसलिए नोड्स में गतिशील रूप से स्पॉन कार्यों में से एक का उपयोग करना आसान है:

# On the remote node
Task.Supervisor.start_link(name: MyApp.DistSupervisor)

# On the client
Task.Supervisor.async({MyApp.DistSupervisor, :[email protected]},
                      MyMod, :my_fun, [arg1, arg2, arg3])

ध्यान दें कि, वितरित कार्यों के साथ काम करते समय, किसी को Task.Supervisor.async/2 बजाय Task.Supervisor.async/4 फ़ंक्शन का उपयोग करना चाहिए, जो कार्य के बजाय Task.Supervisor.async/2 का काम करता है। ऐसा इसलिए है क्योंकि अनाम फ़ंक्शंस में सभी शामिल नोड्स पर समान मॉड्यूल संस्करण मौजूद होने की उम्मीद है। वितरित प्रक्रियाओं पर अधिक जानकारी के लिए Agent मॉड्यूल प्रलेखन की जाँच करें क्योंकि वहाँ वर्णित सीमाएँ पूरे पारिस्थितिकी तंत्र पर लागू होती हैं।

सारांश

प्रकार

t()

कार्य

%Task{}

कार्य संरचना

async/1

एक कार्य शुरू करता है जिस पर प्रतीक्षा की जानी चाहिए

async (मॉड, मज़ा, आर्ग्स)

एक कार्य शुरू करता है जिस पर प्रतीक्षा की जानी चाहिए

async_stream (असंख्य, मज़ेदार, विकल्प \\ []]

एक स्ट्रीम देता है जो दिए गए फ़ंक्शन को प्रत्येक आइटम पर समवर्ती fun करता fun

async_stream (असंख्य, मॉड्यूल, फ़ंक्शन, आर्ग्स, विकल्प \\ [])

एक स्ट्रीम देता है जो दिए गए module , function चलाता है, और प्रत्येक आइटम पर args समरूपता में enumerable

await/2

किसी कार्य के उत्तर की प्रतीक्षा करता है और उसे वापस करता है

child_spec/1

सुपरवाइज़र के तहत कार्य शुरू करने के लिए एक विनिर्देश देता है

शटडाउन (कार्य, शटडाउन \\ 5000)

कार्य को अनलिंक और शट डाउन करता है, और फिर उत्तर की जांच करता है

start(fun)

एक कार्य शुरू करता है

स्टार्ट (मॉड, फन, आर्ग्स)

एक कार्य शुरू करता है

start_link/1

वर्तमान प्रक्रिया से जुड़ी एक प्रक्रिया शुरू करता है

start_link (मॉड, मज़ा, आर्ग्स)

एक पर्यवेक्षण वृक्ष के हिस्से के रूप में एक कार्य शुरू करता है

उपज (कार्य, टाइमआउट \\ 5000)

किसी कार्य उत्तर की प्रतीक्षा में वर्तमान प्रक्रिया को अस्थायी रूप से अवरुद्ध करता है

यील्ड_मनी (कार्य, टाइमआउट \\ 5000)

दिए गए समय अंतराल में कई कार्यों के लिए पैदावार

प्रकार

टी ()

t() :: %Task{owner: term(), pid: term(), ref: term()}

कार्य

% टास्क {} (संरचना)

कार्य संरचना।

इसमें ये फ़ील्ड शामिल हैं:

  • :pid - कार्य प्रक्रिया का PID; nil यदि कार्य किसी कार्य प्रक्रिया का उपयोग नहीं करता है

  • :ref - कार्य मॉनिटर संदर्भ

  • :owner - कार्य शुरू करने वाली प्रक्रिया का पीआईडी

async (मज़ा)

async((() -> any())) :: t()

एक कार्य शुरू करता है जिस पर प्रतीक्षा की जानी चाहिए।

यह फ़ंक्शन एक प्रक्रिया को जन्म देता है जो कॉलर प्रक्रिया से जुड़ा हुआ है और निगरानी करता है। एक Task स्ट्रक्चर को संबंधित जानकारी सहित लौटा दिया जाता है।

async/1 और async/3 सामान्य उपयोग के बारे में अधिक जानकारी के लिए Task मॉड्यूल प्रलेखन पढ़ें।

async/3 भी देखें।

async (मॉड, मज़ा, आर्ग्स)

async(module(), atom(), [term()]) :: t()

एक कार्य शुरू करता है जिस पर प्रतीक्षा की जानी चाहिए।

एक Task स्ट्रक्चर को संबंधित जानकारी सहित लौटा दिया जाता है। डेवलपर्स को अंततः Task.await/2 या Task.yield/2 कॉल करना चाहिए और उसके बाद Task.shutdown/2 को लौटाए गए कार्य पर।

async/1 और async/3 सामान्य उपयोग के बारे में अधिक जानकारी के लिए Task मॉड्यूल प्रलेखन पढ़ें।

लिंक करना

यह फ़ंक्शन एक प्रक्रिया को जन्म देता है जो कॉलर प्रक्रिया से जुड़ा हुआ है और निगरानी करता है। लिंकिंग भाग महत्वपूर्ण है क्योंकि यह कार्य को रोक देता है यदि मूल प्रक्रिया मर जाती है। इससे पहले कि आप async कॉल जोड़ने के बाद async / wait में समान गुण हो, इससे पहले यह कोड की गारंटी देता है। उदाहरण के लिए, कल्पना कीजिए कि आपके पास यह है:

x = heavy_fun()
y = some_fun()
x + y

अब आप heavy_fun() async बनाना चाहते हैं:

x = Task.async(&heavy_fun/0)
y = some_fun()
Task.await(x) + y

पहले की तरह, यदि heavy_fun/0 विफल रहता है, तो पूरी गणना विफल हो जाएगी, जिसमें मूल प्रक्रिया भी शामिल है। यदि आप नहीं चाहते हैं कि कार्य विफल हो जाए, तो आपको heavy_fun/0 कोड को उसी तरह बदलना होगा, जिस तरह से आपको heavy_fun/0 कॉल नहीं होने पर इसे प्राप्त करना होगा। उदाहरण के लिए, या तो लौटने के लिए {:ok, val} | :error {:ok, val} | :error परिणाम या, अधिक चरम मामलों में, try/rescue का उपयोग करके। दूसरे शब्दों में, एक अतुल्यकालिक कार्य को सभी त्रुटियों से अलग करने के लिए एक तंत्र के बजाय एक प्रक्रिया के विस्तार के रूप में सोचा जाना चाहिए।

यदि आप कॉलर को कार्य से लिंक नहीं करना चाहते हैं, तो आपको Task.Supervisor साथ पर्यवेक्षित कार्य का उपयोग करना होगा और Task.Supervisor.async_nolink/2 कॉल Task.Supervisor.async_nolink/2

किसी भी मामले में, निम्नलिखित में से किसी से बचें:

  • सेटिंग :trap_exit to true - ट्रैपिंग निकास का उपयोग केवल विशेष परिस्थितियों में किया जाना चाहिए क्योंकि यह आपकी प्रक्रिया को न केवल कार्य से बल्कि किसी अन्य प्रक्रिया से बाहर निकलने के लिए प्रतिरक्षा बना देगा।

    इसके अलावा, यहां तक ​​कि जब ट्रैपिंग बाहर निकलती है, तब भी कॉलिंग वेट तब भी बाहर निकल जाएगी, जब कार्य को उसके परिणाम को भेजे बिना समाप्त कर दिया गया हो।

  • कार्य प्रक्रिया को अनलिंक करना async / await साथ शुरू हुआ। यदि आप प्रक्रियाओं को अनलिंक करते हैं और कार्य किसी पर्यवेक्षक से संबंधित नहीं है, तो माता-पिता की मृत्यु होने पर आप लटकते कार्यों को छोड़ सकते हैं।

संदेश स्वरूप

कार्य द्वारा भेजा गया उत्तर प्रारूप {ref, result} , जहां ref कार्य संरचना द्वारा आयोजित मॉनिटर संदर्भ है और result कार्य फ़ंक्शन का रिटर्न मान है।

async_stream (असंख्य, मज़ेदार, विकल्प \\ []) (1.4.0 के बाद से)

async_stream(Enumerable.t(), (term() -> term()), keyword()) :: Enumerable.t()

एक स्ट्रीम देता है जो दिए गए फ़ंक्शन को प्रत्येक आइटम पर समवर्ती fun करता fun

प्रत्येक enumerable आइटम को दिए गए फंक्शन को तर्क के रूप में पारित किया जाता fun और अपने स्वयं के कार्य द्वारा संसाधित किया जाता है। कार्यों को वर्तमान प्रक्रिया से जोड़ा जाएगा, इसी तरह async/1

उदाहरण

प्रत्येक स्ट्रिंग में कोडपॉइंट्स को एसिंक्रोनस रूप से गिनें, फिर गणना को घटाकर एक साथ जोड़ें।

iex> strings = ["long string", "longer string", "there are many of these"]
iex> stream = Task.async_stream(strings, fn text -> text |> String.codepoints() |> Enum.count() end)
iex> Enum.reduce(stream, 0, fn {:ok, num}, acc -> num + acc end)
47

चर्चा, विकल्प और अधिक उदाहरणों के लिए async_stream/5 देखें।

async_stream (अनगिनत, मॉड्यूल, फ़ंक्शन, आर्ग, विकल्प \\ []) (1.4.0 के बाद से)

async_stream(Enumerable.t(), module(), atom(), [term()], keyword()) ::
  Enumerable.t()

एक स्ट्रीम देता है जो दिए गए module , function चलाता है, और प्रत्येक आइटम पर args समरूपता में enumerable

प्रत्येक आइटम को दिए गए आर्गन्स के लिए तैयार किया जाएगा और अपने स्वयं के कार्य द्वारा संसाधित किया जाएगा। कार्यों को एक मध्यवर्ती प्रक्रिया से जोड़ा जाएगा जो बाद में वर्तमान प्रक्रिया से जुड़ा हुआ है। इसका अर्थ है किसी कार्य में विफलता वर्तमान प्रक्रिया को समाप्त कर देती है और वर्तमान प्रक्रिया में विफलता सभी कार्यों को समाप्त कर देती है।

जब स्ट्रीम किया जाता है, तो प्रत्येक कार्य सफल पूर्ण होने पर {:ok, value} उत्सर्जन करेगा या यदि कॉलर बाहर निकल रहा है तो {:exit, reason} । परिणाम मूल enumerable के समान क्रम में उत्सर्जित होते हैं।

समसामयिकता के स्तर को इसके माध्यम से नियंत्रित किया जा सकता है :max_concurrency विकल्प और :max_concurrency System.schedulers_online/0 डिफॉल्ट। किसी कार्य उत्तर के बिना प्रतीक्षा करने के लिए अधिकतम समय का प्रतिनिधित्व करने वाले विकल्प के रूप में एक टाइमआउट भी दिया जा सकता है।

अंत में, पर्यवेक्षक के तहत कार्य शुरू करने के लिए Task.Supervisor.async_stream/6 का उपयोग करने पर विचार करें। यदि आप अपने आप को Task.Supervisor.async_stream_nolink/6 स्ट्रीम के अंदर से बाहर निकलने के लिए ट्रैपिंग Task.Supervisor.async_stream_nolink/6 , तो कार्य को शुरू करने के लिए Task.Supervisor.async_stream_nolink/6 का उपयोग करें, जो वर्तमान प्रक्रिया से जुड़े नहीं हैं।

विकल्प

  • :max_concurrency - एक ही समय में चलाने के लिए अधिकतम कार्य सेट करता है। Defaults to System.schedulers_online/0
  • :ordered - क्या परिणाम उसी क्रम में वापस किए जाने चाहिए जैसे इनपुट स्ट्रीम। यह विकल्प तब उपयोगी होता है जब आपके पास बड़ी धाराएँ हों और वे वितरित होने से पहले परिणामों को बफर नहीं करना चाहते। true अवहेलना।
  • :timeout - अधिकतम कार्य (मिलीसेकंड में) प्रत्येक कार्य के लिए निष्पादित करने की अनुमति है। 5000 कमी।
  • :on_timeout - जब कोई कार्य समय समाप्त हो जाता है तो क्या करें। संभावित मूल्य हैं:

    • :exit (डिफ़ॉल्ट) - वह प्रक्रिया जिससे कार्य समाप्त होते हैं।
    • :kill_task - जो कार्य समाप्त हो गया है उसे मार दिया गया है। उस कार्य के लिए उत्सर्जित मूल्य {:exit, :timeout}

उदाहरण

आइए एक स्ट्रीम बनाएं और फिर इसे एन्यूमरेट करें:

stream = Task.async_stream(collection, Mod, :expensive_fun, [])
Enum.to_list(stream)

समसामयिक विकल्प :max_concurrency विकल्प का उपयोग करके बढ़ाया या घटाया जा सकता है। उदाहरण के लिए, यदि कार्य IO भारी हैं, तो मान बढ़ाया जा सकता है:

max_concurrency = System.schedulers_online * 2
stream = Task.async_stream(collection, Mod, :expensive_fun, [], max_concurrency: max_concurrency)
Enum.to_list(stream)

प्रतीक्षा करें (कार्य, टाइमआउट \\ 5000)

await(t(), timeout()) :: term() | no_return()

किसी कार्य के उत्तर की प्रतीक्षा करता है और उसे वापस करता है।

यदि कार्य प्रक्रिया मर जाती है, तो वर्तमान प्रक्रिया कार्य के समान कारण से बाहर निकल जाएगी।

मिलीसेकंड में एक टाइमआउट 5000 डिफ़ॉल्ट मान के साथ दिया जा सकता है। यदि टाइमआउट पार हो गया है, तो वर्तमान प्रक्रिया से बाहर निकल जाएगा। यदि कार्य प्रक्रिया को वर्तमान प्रक्रिया से जोड़ा जाता है जो तब होता है जब कोई कार्य async साथ शुरू किया जाता है, तो कार्य प्रक्रिया भी बाहर निकल जाएगी। यदि कार्य प्रक्रिया बाहर निकल रही है या वर्तमान प्रक्रिया से जुड़ी नहीं है, तो यह चलती रहेगी।

यह फ़ंक्शन मानता है कि कार्य का मॉनीटर अभी भी सक्रिय है या मॉनिटर का :DOWN संदेश कतार में है। यदि यह विमुद्रीकृत कर दिया गया है, या पहले से प्राप्त संदेश है, तो यह फ़ंक्शन संदेश की प्रतीक्षा कर रहे टाइमआउट की अवधि की प्रतीक्षा करेगा।

यह फ़ंक्शन किसी भी दिए गए कार्य के लिए केवल एक बार कॉल किया जा सकता है। यदि आप कई बार जांचना चाहते हैं कि क्या लंबे समय से चल रहे काम ने अपनी गणना पूरी कर ली है, तो इसके बजाय yield/2 उपयोग करें।

ओटीपी व्यवहार के साथ संगतता

GenServer जैसे OTP व्यवहार के अंदर लंबे समय तक चलने वाले कार्य की await करने की अनुशंसा नहीं की जाती है। इसके बजाय, आपको अपने GenServer.handle_info/2 कॉलबैक के अंदर एक कार्य से आने वाले संदेश पर मेल खाना चाहिए।

उदाहरण

iex> task = Task.async(fn -> 1 + 1 end)
iex> Task.await(task)
2

child_spec (arg) (1.5.0 से)

सुपरवाइज़र के तहत कार्य शुरू करने के लिए एक विनिर्देश देता है।

Supervisor देखें।

शटडाउन (कार्य, शटडाउन \\ 5000)

shutdown(t(), timeout() | :brutal_kill) ::
  {:ok, term()} | {:exit, term()} | nil

कार्य को अनलिंक और शट डाउन करता है, और फिर उत्तर की जांच करता है।

रिटर्न {:ok, reply} अगर टास्क को बंद करते समय रिप्लाई मिल जाता है तो, {:exit, reason} अगर टास्क की मौत हो गई, नहीं तो nil

दूसरा तर्क या तो टाइमआउट है या :brutal_kill timeout मामले में :shutdown a :shutdown एग्जिट सिग्नल को टास्क प्रोसेस में भेजा जाता है और अगर यह टाइमआउट से बाहर नहीं निकलता है, तो इसे मार दिया जाता है। के साथ :brutal_kill कार्य को सीधे मार दिया जाता है। यदि कार्य असामान्य रूप से समाप्त हो जाता है (संभवतः किसी अन्य प्रक्रिया द्वारा मारा जाता है), तो यह फ़ंक्शन उसी कारण से बाहर निकल जाएगा।

जब तक कारण से बाहर नहीं निकलता है :normal यह कार्य को कॉल करने की आवश्यकता नहीं है, जब तक कि कारण के साथ बाहर नहीं निकलता :normal या यदि कार्य बाहर निकल रहा है। यदि कॉल करने वाला इसके अलावा किसी अन्य कारण से बाहर निकल रहा है :normal और कार्य बाहर नहीं फंस रहा है, तो कॉल करने वाले के बाहर निकलने का संकेत कार्य को रोक देगा। कॉलर कारण के साथ बाहर निकल सकता है :shutdown कार्यों से जुड़ी अपनी सभी लिंक की गई प्रक्रियाओं को बंद :shutdown लिए शटडाउन, जिसमें कोई लॉग संदेश उत्पन्न किए बिना निकास फँसाना नहीं है।

यदि किसी कार्य का मॉनीटर पहले ही ध्वस्त हो चुका है या प्राप्त हो चुका है और संदेश कतार में प्रतीक्षा की कोई प्रतिक्रिया नहीं है, तो यह फ़ंक्शन वापस लौटेगा {:exit, :noproc} परिणाम या निकास का कारण निर्धारित नहीं किया जा सकता है।

शुरू (मज़ा)

start((() -> any())) :: {:ok, pid()}

एक कार्य शुरू करता है।

इसका उपयोग केवल तब किया जाता है जब कार्य साइड-इफेक्ट्स के लिए उपयोग किया जाता है (अर्थात लौटे परिणाम में कोई दिलचस्पी नहीं है) और इसे वर्तमान प्रक्रिया से नहीं जोड़ा जाना चाहिए।

स्टार्ट (मॉड, फन, आर्ग्स)

start(module(), atom(), [term()]) :: {:ok, pid()}

एक कार्य शुरू करता है।

इसका उपयोग केवल तब किया जाता है जब कार्य साइड-इफेक्ट्स के लिए उपयोग किया जाता है (अर्थात लौटे परिणाम में कोई दिलचस्पी नहीं है) और इसे वर्तमान प्रक्रिया से नहीं जोड़ा जाना चाहिए।

start_link (मज़ा)

start_link((() -> any())) :: {:ok, pid()}

वर्तमान प्रक्रिया से जुड़ी एक प्रक्रिया शुरू करता है।

इसका उपयोग अक्सर पर्यवेक्षण पेड़ के हिस्से के रूप में प्रक्रिया शुरू करने के लिए किया जाता है।

start_link (मॉड, मज़ा, आर्ग्स)

start_link(module(), atom(), [term()]) :: {:ok, pid()}

एक पर्यवेक्षण वृक्ष के हिस्से के रूप में एक कार्य शुरू करता है।

उपज (कार्य, टाइमआउट \\ 5000)

yield(t(), timeout()) :: {:ok, term()} | {:exit, term()} | nil

किसी कार्य उत्तर की प्रतीक्षा में वर्तमान प्रक्रिया को अस्थायी रूप से अवरुद्ध करता है।

रिटर्न {:ok, reply} अगर nil , तो अगर कोई जवाब नहीं आया है तो nil , या {:exit, reason} अगर टास्क पहले ही {:exit, reason} हो गया है। ध्यान रखें कि आम तौर पर एक कार्य विफलता भी प्रक्रिया से बाहर निकलने के लिए काम का कारण बनता है। इसलिए यह फ़ंक्शन {:exit, reason} if {:exit, reason} तभी लौटा सकता है

  • कार्य प्रक्रिया कारण के साथ बाहर निकल गई :normal
  • यह कॉलर से जुड़ा नहीं है
  • कॉल करने वाला बाहर निकल रहा है

मिलीसेकंड में एक टाइमआउट 5000 डिफ़ॉल्ट मान के साथ दिया जा सकता है। यदि कार्य से संदेश प्राप्त होने से पहले समय समाप्त हो जाता है, तो यह फ़ंक्शन nil हो जाएगा और मॉनिटर सक्रिय रहेगा। इसलिए yield/2 को एक ही कार्य पर कई बार कहा जा सकता है।

यह फ़ंक्शन मानता है कि कार्य का मॉनीटर अभी भी सक्रिय है या मॉनिटर का :DOWN संदेश कतार में है। यदि यह विमुद्रीकृत कर दिया गया है या पहले से प्राप्त संदेश है, तो यह फ़ंक्शन संदेश की प्रतीक्षा कर रहे समय समाप्ति की अवधि की प्रतीक्षा करेगा।

यदि आप कार्य को बंद करने का इरादा रखते हैं यदि उसने timeout मिलीसेकंड के भीतर जवाब नहीं दिया है, तो आपको इसे shutdown/1 साथ एक साथ चेन करना चाहिए, जैसे:

case Task.yield(task, timeout) || Task.shutdown(task) do
  {:ok, result} ->
    result
  nil ->
    Logger.warn "Failed to get a result in #{timeout}ms"
    nil
end

यह सुनिश्चित करता है कि यदि कार्य timeout होने के बाद पूरा हो जाता है, लेकिन shutdown/1 को कॉल shutdown/1 से पहले, आपको अभी भी परिणाम मिलेगा, क्योंकि shutdown/1 को इस मामले को संभालने और परिणाम को वापस करने के लिए डिज़ाइन किया गया है।

यील्ड_मनी (कार्य, टाइमआउट \\ 5000)

yield_many([t()], timeout()) :: [
  {t(), {:ok, term()} | {:exit, term()} | nil}
]

दिए गए समय अंतराल में कई कार्यों के लिए पैदावार।

यह फ़ंक्शन कार्यों की एक सूची प्राप्त करता है और दिए गए समय अंतराल में उनके उत्तरों की प्रतीक्षा करता है। यह दो तत्वों के tuples की सूची देता है, पहले तत्व के रूप में कार्य और दूसरे के रूप में उपज परिणाम।

इसी तरह yield/2 , प्रत्येक कार्य का परिणाम होगा

  • {:ok, term} यदि कार्य ने दिए गए समय अंतराल में अपने परिणाम को सफलतापूर्वक रिपोर्ट किया है
  • {:exit, reason} यदि कार्य समाप्त हो गया है तो {:exit, reason}
  • nil यदि कार्य समय-सीमा के दौरान चालू रहता है

अधिक जानकारी के लिए yield/2 जाँच करें।

उदाहरण

Task.yield_many/2 डेवलपर्स को कई कार्यों को स्पॉन करने और किसी दिए गए समय सीमा में प्राप्त परिणामों को पुनः प्राप्त करने की अनुमति देता है। अगर हम इसे Task.shutdown/2 साथ Task.shutdown/2 , तो यह हमें उन परिणामों को इकट्ठा करने और उन कार्यों को रद्द करने की अनुमति देता है, Task.shutdown/2 समय पर जवाब नहीं दिया है।

एक उदाहरण देखते हैं।

tasks =
  for i <- 1..10 do
    Task.async(fn ->
      Process.sleep(i * 1000)
      i
    end)
  end

tasks_with_results = Task.yield_many(tasks, 5000)

results = Enum.map(tasks_with_results, fn {task, res} ->
  # Shutdown the tasks that did not reply nor exit
  res || Task.shutdown(task, :brutal_kill)
end)

# Here we are matching only on {:ok, value} and
# ignoring {:exit, _} (crashed tasks) and `nil` (no replies)
for {:ok, value} <- results do
  IO.inspect value
end

ऊपर दिए गए उदाहरण में, हम ऐसे कार्यों का निर्माण करते हैं जो 1 से 10 सेकंड तक सोते हैं और वे कितने सेकंड सोते हैं। यदि आप एक ही बार में कोड निष्पादित करते हैं, तो आपको 1 से 5 तक मुद्रित दिखाई देना चाहिए, क्योंकि वे कार्य थे जो दिए गए समय में उत्तर दिए हैं। Task.shutdown/2 कॉल का उपयोग करके अन्य सभी कार्य बंद कर दिए Task.shutdown/2