پروسس ها در الکسیر

سلام
از اونجایی که مبحث پروسس ها و همزمانی تو الکسیر خیلی برای من سنگینه و شاید دوستان دیگری هم به مشکل بربخورن وجود این صفحه الزامیه.
خب اولین سوالم اینه تا جایی که اطلاع دارم garbage collector ماشین BEAM کاری با اتم ها نداره .حالا سوال اینجاست وقتی از اتم ها در GenServer استفاده میکنیم در صورتی که زیاد بشن ممکنه مشکل بوجود بیارن یا نه ؟ در کل از اتم ها کی و چجوری استفاده کنیم به مشکل بر نخوریم ؟

سوال دوم :

iex(12)> :gen_server.
abcast/2 abcast/3 behaviour_info/1
call/2 call/3 cast/2
enter_loop/3 enter_loop/4 enter_loop/5
format_status/2 init_it/6 module_info/0
module_info/1 multi_call/2 multi_call/3
multi_call/4 reply/2 start/3
start/4 start_link/3 start_link/4
stop/1 stop/3 system_code_change/4
system_continue/3 system_get_state/1 system_replace_state/2
system_terminate/4 wake_hib/5
iex(12)>
nil
iex(13)>
nil
iex(14)> GenServer.
abcast/2 abcast/3 call/2 call/3
cast/2 multi_call/2 multi_call/3 multi_call/4
reply/2 start/2 start/3 start_link/2
start_link/3 stop/1 stop/2 stop/3
whereis/1
iex(14)>

چرا باید توابع :gen_server تعدادشون با GenServer فرق داشته باشه ؟

So why have both GenServer and :gen_server? Well, GenServer does two things for us.

(For those of you wondering, all module names in Elixir are converted to atoms. For example, the TodoList module is converted to :“Elixir.TodoList” and GenServer is converted to :“Elixir.GenServer”. Erlang modules are not namespaced under Elixir, which is why we refer to simply :gen_server).

First, it injects @behaviour :gen_server into our module, so that our module must implement the functions expected by :gen_server. (We’ll come back to that in a second). More importantly, however, GenServer also provides default implementations of the functions demanded by :gen_server, and makes these default implementations overridable (see Line 44). This way, we only have to provide implementations of the functions that we care about, which will “over-ride” the defaults.

Finally, GenServer provides a more pleasing API than what would be required by Erlang. For example, we can call GenServer.start/3 instead of :gen.start/6.

خب این لینکو خوندم و فهمیدم ماژول GenServer خیلی کارها رو راحتتر کرده ولی بازم دقیق متوجه نشدم چرا باید توابع تعدادشون کمتر باشه ؟ دونستن این توابع اضافی بدرد میخوره یا چون لازم نیستن داخل GenServer وجود ندارن؟

1 پسندیده

gen_server: کتابخانه Erlang هست و GenServer کتابخانه Elixir
Elixir اکثر توابع gen_server: داره ولی نه تمامشو
اگرکتابخانه Erlang بخوای استفاده کنی با اتم ها اینکارو میکنی
math.pi:

2 پسندیده

سلام ممنون از پاسختون اما اشتباه متوجه شدین سوالمو و چیزایی که اشاره کردین رو میدونستم البته فک کنم اشتباه از منه سوالمو نتونستم خوب مطرح کنم بهرحال سوالم اینه که تا جایی که میدونم تو الکیسر اومدن دوباره gen_server ارلنگ رو بازنویسی کردن و از یه سری implement اضافی جلوگیری کردن و نتیجش شده GenServer . تا اینجای کار رو فهمیدم اما چرا تعداد توابع اینا یکسان نیست؟علتش اینه که توابع gen_server بیهوده بودن که تو GenServer وجود نداره؟ندونستن این توابع اضافی مشکل ایجاد نمیکنه ؟
سوال دوم : garbage collector با اتم ها کاری نداره از طرفی تو GenServer یا کدی که فرضا خودمون میزنیم از اتم استفاده میکنم مثلا اگر چهارتا handle_call داشته باشم با request های مختلف که هر کدومش یک اتم هست و بعد فرضا داخل ی تابع بازگشتی با GenServer.call یکی از این توابعو صدا کنم به ازای هر دور تابع آیا یه اتم درست میشه ؟این اتم چون garbage collector بهش دست نمیزنه کجا میره چی میشه ممکنه زیاد بشه out of memory بشه؟

1 پسندیده
defmodule Gen do
	
	defmacro __using__(_) do
		quote do
			def put(s),do: IO.puts s
		end
	end
end
defmodule S do
	use Gen
end
Gen
S.put "helo"

هرچقدر بیشتر میرم جلو بیشتر عاشق این زبان میشم

Elixir نمیخواسته تمام توابعرو و چون زبان کوچکتریه یا دلایل دیگه . اتم در کد مشکلی نداره ولی اتم نبایدبرای داده کاربر های خارجی استفاده بشه اتمها برای سمبل هادر کد به کار میرن

2 پسندیده

آها طوری که من از کتاب های که خوندم و وبلاگ و… متوجه شدم تو پروسس ها و همزمانی مجبوریم علاوه بر ماژول های خود الکسیر ماژول های ارلنگ رو هم مطالعه کنیم و بهتره رو این موارد هم کار کنم . جالبش اینه حتی تو بعضی از کتاب ها هم که آموزش الکسیر بودن از ماژول های خود ارلنگ استفاده میکرد که فکر کنم در آینده ای نه چندان دور تیم الکسیر براشون ماژول بنویسه .
راستی جمله " اتم نباید برای داده کاربرهای خارجی استفاده بشه" منظور از داده کاربر خارجی کدی هست که بیرون از GenServer استفاده میشه یا Node دیگه ای که قراره وصل بشه به این نود یا کلا منظورتون اینه تو بیرون مثلاً از کاربر ورودی میگیرم یا روی داده ها پردازش خاضی انجام میدم اون وقت از اتم استفاده نکنیم ؟
سوال سوم : آیا غیر LAN راه ارتباطی دیگه ای هم برای 2 Node مختلف وجود داره ؟ مثلا یه Node سروش تو آلمان باشه اون یکی تو ایران و از طریق اینترنت بشه دو ماشین beam رو بهم وصل کرد ؟ از شبکه خوب سردرنمیارم اما این مبحث خیلی کنجکاوم کرده

1 پسندیده

منظورم کلا ورودی کاربر بود
Node میتونه هرجا باشه اما latency زیاد میشه هرچه فاصله بیشترباشه

1 پسندیده

:heart_eyes::heart_eyes::heart_eyes:سپاسگذارتونم واقعا ممنون انشالله بشه جبران کنیم

1 پسندیده

@shahryarjb
@samdvr
@toomaj

این فریم ورک رو دیدین ؟ http://sugar-framework.github.io/docs/controllers/
واقعا جالبه و اسمش خیلی بهش میاد

3 پسندیده

من نديده بودم، جالب بود

1 پسندیده

سلام :wink:
میشه یکم init رو در داخل Supervisor توضیح بدین ؟ متاسفانه در موردش خیلی کم نوشته شده مثلا :
> defmodule Mdl do
> def start_link(args) do
> Supervisor.start_link MODULE,[args]
> end
> def init(_) do
> child = [
> worker(…)
> ]
> supervise child,strategy: …
end

خب تو مثال کار supervise داخل تابع init چیه ؟‌ اگر میشه از worker یا superviser در داخل start_link هم استفاده یا تعریف کنیم یا داخل توابع دیگه چرا داخل init استفاده کرده ؟‌ کلا اگر init رو توضیح بدین ممنون میشم :slight_smile:

سلام، فكر كنم @samdvr در اين مورد يكمى گفت اما دركش كمى سخته، يكمى رو actor model و concurrency در ارلنگ مطالعه كنيد، بعدش از اونجا ميشه شروع كرد,

http://theerlangelist.blogspot.com.au/2013/01/actors-in-erlangelixir.html?m=1

1 پسندیده

بله میدونم ولی در مورد init چیزی نگفتن و اون متن رو که گفتین خوندم . خود init رو میدونستم چیه فقط اینکه باید چطور توش کد زد رو دقیق خبر نداشتم اونم الان خیلی اتفاقی خودم فهمیدم . actor‌ و … رو تا حدودی فهمیدم و خوبم پیش رفتم باید بگم به معنای واقعی خفنه و فکر نکنم دیگه احتیاجی به redis و… پیدا کرد با حضور GenServer . در مورد اکتور هم همین کتاب خوب توضیح داده و تونستم یه چت سرور خیلی ساده پیاده کنم که از طریق یه supervisor نظاره میشه و در صورت از کار افتادن دوباره ریستارت میشه و در این وسط یه کارگر دیگه هست که چت ها رو نگه میداره تا در صورت شروع دوباره چت سرور از کارگر پیام ها رو برداره اما متاسفانه کتاب ها حتی خود وب سایت الکسیر در مورد جزیات بخصوص در مورد توابع GenServer و سوپروایزر یکم کم لطفی کردن و اگر منبعی دارین که جزیات رو خوب توضیح داده باشه واقعا ممنون میشم به اشتراک بزارین. تو تمام عمرم اولین باره تاسف میخورم که چرا از وجود چنین چیزهای خارق العاده ای بی خبر بودم٫

آهان ببخشيد، فكر كنم بهتره خودشون جواب بدم چون مثال ايشون بود

cc @samdvr

1 پسندیده

@toomaj گفتن اینم خوب نیست اما متاسفانه حتی بعضی از نویسنده های کتاب ها هم خیلی تابلو هست که در این چیزها تازه واردن و خودشونم درست حسابی نمیدونن چی به چیه . تازه الکسیر خودش هم در این مورد یکم ضعف داره .

Supervisor.start_child(sup,worker(Ana.DB,[args]))

کد بالا رو در نظر بگیرین . من درست ۳ ساعت بخاطر ۲ تا براکت علاف شدم و کم موند سرمو بکوبم دیوار. بدون خطا کامپایل میشد بدون خطا خطا شروع میکرد و هیچ مشکلی نداشت اما وقتی پروسس ها رو صدا میکردم میگفت هیچ پروسه ای هنوز شروع به فعالیت نکرده و بالاخره بعد از ۳ ساعت فهمیدم بخاطر اینه که args رو بدون براکت نوشتم و باید بجاش بنویسم [args] .

1 پسندیده

سلام
Init در GenServer حالت اولیه سرور و تعریف میکنه مثلا چه داده و لود کن و… در supervisor ها وجود init برای تعریف فرزندان که زیر نظر هستند و. نوع ریستارت هستش هر ماژول فرزند باید start_link داشته باشه که وقتی ریستارت میشه این فانکشن فراخوانی میشه با ارگومنت هایی که درsupervisor تعریف شده
فرزندان یا worker هستندیا supervisor

defmodule MyApp.Supervisor do
  use Supervisor

  def start_link do
    Supervisor.start_link(__MODULE__, [])
  end

  def init([]) do
    children = [
      worker(KV.Registry, [KV.Registry]),
      supervisor(KV.Bucket.Supervisor, [])
    ]

    supervise(children, strategy: :one_for_one)
  end
end

شما اگه کتاب Elixir In Action و بخونی خوب توضیح داده

2 پسندیده

واقعا ممنون . بله کتاب خیلی خوبیه و توصفحه ۸۵ این کتاب هستم . بازم ممنون

2 پسندیده

درود خدمت دوستان و اساتید محترم . @toomaj @samdvr

من از اینترنت چندین مطلب در مورد ایجنت و پروسز خوندم و مثال هاشو هم تست زدم البته نا گفته نماند که اصلا از تسک هیچی نفهمیدم :smiley: نمی دونم چرا به هر صورت :wink:

مشکل اصلی اینکه ما خیلی از این مثال هارو می زنیم و خوب انجام می دم تا اینجا اوکی و می دونیم که می شه با پروسز مثلا ۳ تا کار رو همزمان استارت زد و دیگه منتظر اینکه یکی تمام بشه نمونیم .

ولی یک مثال خوب کاربردی که بشه دقیقا فهمید کجا باید استفاده کرد از ایجنت و پروسز تو ذهنم نیست یا انقدر با مثال های پیش پا افتاده برای آموزش کار کردیم قفل شده فکر کم .

اگر دوستان چند مثال داستانی کوتاه در مورد ایجنت - تسک و سوپروایزر - جن سرور بزنند و لطف بکنند بسیار ممنون می شم. آدم درکش بکنه کلیتشو خیلی بهتر یاد می گیره

1 پسندیده

نکته قشنگی رو گفتی و متاسفانه منم هنوزم دقیق نمیدونم GenServer چیه اما اگه برنامه چت ساده بنویسی خیلی چیزا دستگیرت میشه یا یه چیز ساده شبیه redis که key/value باشه . از exrm استفاده کردی ؟:sunglasses: خیلی جالبه حتما استفاده کن هرچند ب بحث ربط نداره.
این لینکو بخون
https://www.google.com/url?sa=t&source=web&rct=j&url=https://medium.com/blackode/when-and-where-to-use-cast-cal-info-messages-in-elixir-erlang-genserver-9baf937b6494&ved=0ahUKEwi-w7HtxvrUAhXBCJoKHZtyDY4QFghBMAE&usg=AFQjCNEMkUSzDapY-HeMtTDz3lNjWjQkSg

البته فیلتره سایتش و طبق ارزش های نظام ظاهرا ناسازگاره

https://blog.drewolson.org/understanding-gen-server/


لین بالایی رو حتما بخون خوب توضیح داده در مورد مدل سازی

منم اگر وقت کنم حتما دونسته هامو باهات share میکنم و انتظار متفابلم دارم که توهم بامن share کنی

1 پسندیده

GenServer یکی از ساختار های اصلی OTP هستش که برای ساختن سرور ها که supervise میشن به کار میره GenServer سه قابلیت کلی داره
۱. ذخیره کردن داده
۲. انجام دادن یک فانکشن به صورت async در یک process جدا
۳. انجام دادن یک فانکشن وصبر کردن برای جواب که شبیه فانکشن sync

به مثال بالا توجه کنید در GenServer دو فانکشن call back برای سرور داره handle_call و handle_cast
handle_call کارو به صورت شبه “sync” انجام میده و handle_cast به صورت async و در process جدا انجام میده

قسمت Client با فانکشن start یا start_link حالت اولیه server و تعریف میکنه handle_cast و handle_call توسط
GenServer.cast و GenServer.call از Client به Server فرستاده میشه این فانکشن ها میتونن هر داده ای که در سرور درست شده رو update کنن

نکته: با مرگ سرور داده ازبین میره
GenServer برای زمانی خوبه که از دست دادن داده مهم نیست مثل Cache یا سرور هایی که state نمیشه همزمان تو دیتابیس گذاشت مثل سرور های بازی با کاربر زیاد و latency کم این سرورها داده ها رو به صورت event با تاخیر در دیتابیس اصلی ذخیره میکنند ولی هنگام بازی هر بازی یک GenServer جداست به این سرویسها Stateful Service میگن

GenServer.cast و GenServer.call اصولا با فانکشن های دیگه پنهان میکنیم برای تمیزیه API

Agent , Task هر دو درواقع GenServer هستند ولی هرکدام قسمتی از کار GenServer و انجام میدن
Task برای اینه که بخوای فانکشنی و async در یک process جدا اجرا کنی

task = Task.async(fn -> 2 * 2 end)
 result = Task.await(task) 

Task.async هر فانکشنی و async اجرا میکنه Task.await برای جواب صبر میکنه

Agent فقط برای ذخیره و تغییر داده هست

GenServer, Task , Agent هرسه میتونن supervise بشن

2 پسندیده