---
title: "استكشاف العمليات (processes) في Elixir"
description: "نبني على مثال FizzBuzz من المقالة السابقة ونطوّره."
canonical: https://oozou.com/ar/blog/exploring-elixir-processes-18
locale: ar
date: 2014-12-16
author: "OOZOU Team"
---

# استكشاف العمليات (processes) في Elixir

> نبني على مثال FizzBuzz من المقالة السابقة ونطوّره.

Published: 2014-12-16 · Author: OOZOU Team (Engineering) · 4 min read

مرّت قرابة 3 أشهر على إصدار Elixir 1.0، وما زلنا [متحمسين جدًا لهذه اللغة](https://oozou.com/blog/why-we-are-excited-about-elixir-13).

في هذه المقالة نبني على مثال FizzBuzz من المقالة السابقة، ونحوّله الآن إلى خادم.

**خادم FizzBuzz**

```
defmodule FizzBuzz do
  @moduledoc "A very simple FizzBuzz server"

  @doc """
    Computes and outputs the FizzBuzz value for the
    provided argument.
  """
  @spec compute(Integer) :: :ok
  def compute do
    receive do
      n -> IO.puts "#{n}: #{compute(n)}"
    end
    compute
  end

  defp compute(n) do
    case {rem(n, 3), rem(n, 5)} do
      {0, 0} -> :FizzBuzz
      {0, _} -> :Fizz
      {_, 0} -> :Buzz
      _      -> n
    end
  end
end
lang-elixir
```

هذا module بسيط، فيه بعض التوثيق و[typespec](http://elixir-lang.org/docs/stable/elixir/Kernel.Typespec.html) للدالة compute/0، التي تمثل نقطة الدخول الرئيسية إلى module الـ FizzBuzz. تستخدم الدالة [receive/1](http://elixir-lang.org/docs/stable/elixir/Kernel.SpecialForms.html#receive/1) لجلب الرقم التالي من صندوق بريد العملية (mailbox)، ثم تحسب النتيجة (عبر الدالة الخاصة compute/1) وتطبعها، قبل أن تستدعي نفسها مجددًا لانتظار الرسالة التالية.

**التواصل مع الخادم**

لاستخدام الخادم الذي أنشأناه للتو، نبدأ تشغيله أولًا باستخدام [spawn/3](http://elixir-lang.org/docs/stable/elixir/Kernel.html#spawn/3)، التي تتوقع اسم module واسم الدالة المراد استدعاؤها ووسائط تلك الدالة. وتُرجع الـ pid الخاص [بالعملية](http://elixir-lang.org/getting_started/11.html) الجديدة، ونخزّنه في المتغير fb (تذكروا أن الأقواس حول وسائط الدوال اختيارية في Elixir).

```
fb = spawn FizzBuzz, :compute, []
lang-elixir
```

بعد ذلك يمكننا استخدام [send/2](http://elixir-lang.org/docs/stable/elixir/Kernel.html#send/2) لإرسال رسالة إلى الخادم:

```
send fb, 3
lang-elixir
```

سيطبع هذا "3: Fizz" ويُرجع 3. لنرسل الآن عدة رسائل للتأكد من أن الاستدعاء التكراري في compute/0 يعمل كما هو متوقع:

```
10..15 |> Enum.map(&send(fb, &1))
lang-elixir
```

نستخدم هنا عامل الـ pipe في Elixir ([|>/2](http://elixir-lang.org/docs/stable/elixir/Kernel.html#|>/2)) لإرسال [Range](http://elixir-lang.org/docs/stable/elixir/Range) الأرقام من 10 إلى 15 إلى [Enum.map/2](http://elixir-lang.org/docs/stable/elixir/Enum.html#map/2)، التي تستخدم نسخة مطبّقة جزئيًا من send/2 مع وسيط مجهول (&1). والناتج كما توقعنا:

```
10: Buzz
11: 11
12: Fizz
13: 13
14: 14
15: FizzBuzz
lang-elixir
```

**التعامل مع الأخطاء**

قد يتساءل القراء الأكثر انتباهًا الآن: ماذا يحدث لو أرسلنا إلى FizzBuzz.compute/0 نوع بيانات آخر بدلًا من عدد صحيح؟ لنجرب:

```
send fb, 1.0
lang-elixir
```

يؤدي هذا إلى رسالة الخطأ التالية:

```
14:25:32.742 [error] Error in process <0.95.0> with exit value: {badarith,[{'Elixir.FizzBuzz',compute,1,[{file,"fizzbuzz.ex"},{line,10}]},{'Elixir.FizzBuzz',compute,0,[{file,"fizzbuzz.ex"},{line,4}]}]}
lang-elixir
```

يعني هذا أن خادم FizzBuzz قد تعطل. لكن بما أننا نتعامل مع عملية غير مرتبطة (unlinked)، فإن برنامجنا الرئيسي (وهو في هذه الحالة جلسة iex) لا يتأثر بذلك. لنشغّل الخادم مجددًا، لكن هذه المرة [كعملية مرتبطة](http://elixir-lang.org/getting_started/11.html#11.3-links) باستخدام [spawn_link/3](http://elixir-lang.org/docs/stable/elixir/Kernel.html#spawn_link/3):

```
fb = spawn_link FizzBuzz, :compute, []
lang-elixir
```

الآن ستنتقل أي مشكلة في خادم FizzBuzz إلى الأعلى وتُنهي العملية الرئيسية أيضًا:

```
14:33:40.426 [error] Error in process <0.119.0> with exit value: {badarith,[{'Elixir.FizzBuzz',compute,1,[{file,"fizzbuzz.ex"},{line,10}]},{'Elixir.FizzBuzz',compute,0,[{file,"fizzbuzz.ex"},{line,4}]}]}

** (EXIT from #PID<0.116.0>) an exception was raised:
** (ArithmeticError) bad argument in arithmetic expression
fizzbuzz.ex:10: FizzBuzz.compute/1
fizzbuzz.ex:4: FizzBuzz.compute/0
lang-elixir
```

يمكن معالجة ذلك بإضافة guard clause إلى compute/0 في FizzBuzz على هذا النحو:

```
def compute do
  receive do
    n when is_integer(n) -> IO.puts "#{n}: #{compute(n)}"
    _ -> IO.puts "Invalid argument"
  end
  compute
end
lang-elixir
```

ينجح هذا الحل، لكنه يتعارض مع أحد أهم مبادئ Erlang: "let it crash" (دعها تتعطل). فبدلًا من البرمجة الدفاعية، تُنهي الأخطاء العملية ببساطة، وتُترك معالجة الموقف لعمليات المراقبة (إن وُجدت).

**المراقبة (Monitoring)**

إحدى طرق التعامل مع ما سبق هي إعداد monitor. وعلى عكس الـ link، فهذه علاقة أحادية الاتجاه بين العمليات. لإنشاء monitor، نشغّل خادم FizzBuzz باستخدام [spawn_monitor/3](http://elixir-lang.org/docs/stable/elixir/Kernel.html#spawn_monitor/3)، التي تُرجع مرجع مراقبة (monitoring reference) إضافة إلى الـ pid. لا نستخدم هذا المرجع في المثال التالي، لكنه مفيد لإيقاف المراقبة يدويًا عبر استدعاء [demonitor/2](http://elixir-lang.org/docs/stable/elixir/Process.html#demonitor/2).

الآن إذا توقف الخادم، تُرسل رسالة إلى عملية المراقبة:

```
{fb, ref} = spawn_monitor FizzBuzz, :compute, []
send fb, 1.0
lang-elixir
```

بما أننا لم نستخدم receive/1 لإعداد مستقبِل رسائل في جلسة iex، سنحتاج إلى استدعاء الدالة المساعدة [flush/0](http://elixir-lang.org/docs/master/iex/IEx.Helpers.html#flush/0) يدويًا لرؤية تنبيه المراقبة:

```
{:DOWN, #Reference<0.0.0.262>, :process, #PID<0.79.0>,
  {:badarith,
    [{FizzBuzz, :compute, 1, [file: 'fizzbuzz.ex', line: 16]},
    {FizzBuzz, :compute, 0, [file: 'fizzbuzz.ex', line: 10]}]}}
lang-elixir
```

**ما التالي؟**

التعامل مع العمليات في Elixir سهل جدًا. لكن بتنفيذ خادم FizzBuzz من الصفر، لا نستفيد بالكامل من القوة التي توفرها أسس Erlang/OTP للغة Elixir. لذا سنعود في الجزء القادم من هذه السلسلة إلى خادم FizzBuzz، لكن هذه المرة باستخدام سلوكيات OTP [gen_server](http://www.erlang.org/doc/man/gen_server.html) و[supervisor](http://www.erlang.org/doc/man/supervisor.html). تابعونا!

---

Contact OOZOU: hello@oozou.com · +66 2544 0000 · https://oozou.com/ar/contact

More for AI agents: https://oozou.com/llms.txt · every page has a markdown twin at its URL plus ".md"
