ارلنگ
ارلنگ (به انگلیسی: Erlang، /ˈɜːrlæŋ/ UR-lang) یک زبان برنامهنویسی همهمنظوره، همروند، دارای زباله جمعکن و سامانهٔ زماناجرا (به انگلیسی: Runtime) است. برای همروندی از مدل اکتور (به انگلیسی: Actor Model) پیروی میکند. این زبان توسط شرکت اریکسون برای پشتیبانی و توسعه برنامههای توزیعشده، تحملپذیر در برابر خطا، بیدرنگ نرم (به انگلیسی: soft-real-time) و بدون وقفه طراحی شدهاست. اریکسون برای طراحی نرم افزار های سوییچینگ تلفن قبلا از زبانی به نام PLEX استفاده میکرده که این زبان بسیار شبیه Erlang بوده منتهی مشکلاتی داشته که Erlang بطور کامل آنها را رفع کرده. این زبان از تعویض داغ[نیازمند منبع] (به انگلیسی: Hot swapping) که در آن بدون توقف سامانه، قادر به تغییر کدهای برنامه هستیم پشتیبانی میکند.
پارادایم برنامهنویسی | چندالگویی: همزمان، تابعی |
---|---|
طراحی شده توسط | جو آرمسترانگ، روبرت ویردینگ، و مایک ویلیامز |
توسعهدهنده | اریکسون |
ظهوریافته در | ۱۹۸۶ |
انتشار پایدار | 27.1.2[۱]
/ ۱۷ اکتبر ۲۰۲۴ |
نیرومند، پویا | |
پروانه | مجوز آپاچی ۲٫۰ |
.erl, .hrl | |
وبگاه | |
پیادهسازیهای بزرگ | |
Erlang | |
متأثر از | |
پرولوگ، اسمالتاک، PLEX، لیسپ | |
تأثیر گذاشته بر | |
اف شارپ، کلوژر، راست (زبان برنامهنویسی)، اسکالا، اوپا، Reia، الیکسیر (زبان برنامهنویسی)، دارت (زبان برنامهنویسی)، Akka | |
سیستم زمان اجرا ارلنگ برای طراحی سیستم هایی که نیازمند خصوصیات زیر هستند استفاده میشود (به نوع ماشین مجازی ارلنگ این امکانات را دارد):
- توزیع شده (به انگلیسی: Distributed)
- بردباری خطا (به انگلیسی: Fault-tolerant)
- زمان واقعی ملایم (به انگلیسی: Soft real-time)
- بسیار در دسترس، بدون توقف (به انگلیسی: Highly available, non-stop applications)
- تعویض داغ (به انگلیسی: Hot swapping) که در آن کد میتواند بدون توقف سیستم تغییر کند.
زبان برنامهنویسی ارلنگ برای خواص زیر شناخته میشود:
- داده تغییرناپذیر (به انگلیسی: Immutable data)
- تطبیق الگو (به انگلیسی: Pattern matching)
- برنامهنویسی تابعی (به انگلیسی: Functional programming)
ارلنگ در واقع یک زبان اختصاصی در شرکت اریسکون بود که توسط Joe Armstrong، Robert Virding و Mike Williams در سال ۱۹۸۶ توسعه پیدا کرده بود، اما در سال ۱۹۹۸ به عنوان یک زبان متن باز منتشر شد. Erlang/OTP توسط واحد محصول OTP در اریکسون پشتیبانی و نگهداری میشود.
تاریخچه
ویرایشنام «ارلنگ» توسط Bjarne Däcker که سرپرست آزمایشگاه و تیم طراحی ارلنگ بوده انتخاب شده. این نام از دو جهت قابل ملاحظه و جالب هست ابتدا اینکه از نام یک مهندس و ریاضی دان دانمارکی Agner Krarup Erlang گرفته شده که این فرد در زمینه مخابرات هم فرمولی دارد (Erlang formula) و از طرفی هم از مخفف Ericsson Programming Language گرفته شده.ارلنگ با هدف بهبود و توسعه برنامههای کاربردی تلفن طراحی شدهاست. نسخه اولیه ارلنگ در پرولگ (به انگلیسی: Prolog) اجرا شد و توسط زبان برنامهنویسی مورد استفاده در PLEX مبادلات زودتر اریکسون تأثیر پذیرفته بود. در سال ۱۹۸۸ ارلنگ ثابت کرده بود که برای نمونهسازی مبادلات تلفنی مناسب است، اما در prolog بسیار آهسته اجرا میشد. یک گروه از متخصصان اریکسون تخمین زده بودند که برای استفاده از محصولشان سرعت آن باید ۴۰ بار سریعتر شود بنابراین در سال 1992 شروع به بازنویسی آن با زبان C کردند و ماشین مجازی BEAM متولد شد. نحوه عملکرد ماشین مجازی BEAM ترکیبی از کدهای NATIVE و تفسیر مستقیم برای ایجاد تعادل بین حجم کدها و افزایش عملکرد محیط اجرا است. با توجه به گفتههای آرمسترانگ، این زبان زمانی از یک محصول آزمایشگاهی به یک محصول واقعی تبدیل شد که در طراحی نسل جدید AXE به AXE-N در سال ۱۹۹۵ استفاده شد با این موفقیت در نتیجه Erlang برای سویچ های شبکه از نوع ATM (Asynchronous Transfer Mode) هم انتحاب شد.
در سال ۱۹۹۸ اریکسون از سوئیچ AXD301 اطلاع داد، که شامل بیش از یک میلیون خط از ارلنگ میشد و از در دسترس بودن بالای ۹ گزارش داد. مدت کوتاهی پس از آن، سیستم رادیو ارلنگ استفاده از ارلنگ برای محصول جدید در مصارف خانگی را ممنوع کرد، این اتفاق با استناد به اولویت زبانهای غیررسمی روی داد. این ممنوعیت باعث شد آرمسترانگ و دیگران شرکت اریکسون را ترک کنند. اجرای متن بازکردن این زبان در انتهای همین سال روی داد. سرانجام با برداشتن این ممنوعیت اریکسون دوباره آرمسترانگ را در سال ۲۰۰۴ استخدام کرد.
در سال ۲۰۰۶، پشتیبانی از چند پردازندهای متقارن محلی به سیستم زمان اجرا و ماشین مجازی اضافه شد.
جهان بینی ارلنگ
ویرایشدیدگاه ارلنگ از جهان، از زبان جو آرمسترانگ، یکی از سازنده گان ارلنگ که خلاصهای از آن را در پایاننامه دکترای خود به شرح زیر آورده:
- همه چیز یک فرایند است.
- فرایندها به شدت منزوی هستند.
- ایجاد و تخریب فرایند یک عملیات سبکوزن است.
- عبور پیام تنها راه تعامل فرایند هاست.
- فرایندها نامهای منحصر به فردی دارند.
- اگر شما نام یک فرایند را بدانید میتوانید به آن پیام ارسال کنید.
- فرایندها بدون منبع به اشتراک گذاشته میشوند.
- دست زدن به خطا (به انگلیسی: Error handling) غیر محلی است.
- فرایندها کارهایی که پشتیبانی میکنند را انجام میدهند که منجر به انجام یا شکست میشود.
جو آرمسترانگ در سال ۲۰۱۳ در مصاحبه با Rackspace اشاره میکند: «اگر جاوا یک بار نوشته شود و همه جا اجرا شود، پس ارلنگ یک بار نوشته میشود و همیشه اجرا میشود.»
استفاده
ویرایشارلنگ در حال حاضر توسط شرکتها از جمله Cisco, Facebook, Nortel و T-Mobile استفاده شدهاست. ارلنگ در گره پشتیبانی اریکسون، و 3G , GPRS و شبکههای LTE در سرار جهان مورد استفاده قرار میگیرد. در حقیقت بیشتر ترافیک اینترنت بصورت مستقیم یا غیر مستقیم از طریق ارلنگ مدیریت میشود, هر زمان که از تلفن ثابت یا تلفن همراه و یا اینترنت استفاده میکنیم در حقیقت در حال استفاده از ارلنگ هستیم.
[۲][۳]
مفاهیم کلیدی
ویرایشدر Erlang، فرایندها (processes)، پایشها (monitors) و ناظران (supervisors) مفاهیم مهمی برای ساخت برنامههای مقاوم در برابر خطا و قابل مقیاس هستند:[۴]
فرایندها
- فرایندهای Erlang واحدهای اجرای سبک، جداگانه و همزمان هستند.
- آنها با استفاده از توابع `()spawn` ایجاد میشوند و از طریق پیامهای غیرهمزمان با هم ارتباط برقرار میکنند.
- فرایندها میتوانند با استفاده از توابع `register/2` و `whereis/1` تحت نامهای ثبت شده برای آدرسدهی آسانتر ثبت شوند.
پایشها
- پایشها پیوندهای یکطرفه بین فرایندها هستند که به یک فرایند امکان میدهند فرایند دیگری را پایش کند.
- یک پایش با استفاده از `erlang:monitor/2` ایجاد میشود و فرایند پایشکننده پیام `'DOWN'` دریافت میکند اگر فرایند پایششده پایان یابد.
- پایشها برای فرایندهای خارجی که به وضعیت فرایند دیگری علاقهمند هستند اما مسئول مستقیم آن نیستند مفید هستند.
ناظران
- ناظران فرایندهای ویژهای هستند که مجموعهای از فرایندهای فرزند را پایش و کنترل میکنند، که میتوانند کارگران (workers) یا ناظران دیگر باشند.
- ناظران یک استراتژی راهاندازی مجدد برای مدیریت شکستهای فرایندهای فرزند تعریف میکنند، مانند one_for_one (فقط فرزند شکستخورده را راهاندازی مجدد کن)، one_for_all (همه فرزندان را راهاندازی مجدد کن) یا rest_for_one (فرزند شکستخورده و آنهایی را که پس از آن هستند را راهاندازی مجدد کن).
- ناظران با استفاده از یک ماژول بازخورد که توابعی مانند `init/1` را صادر میکند تعریف میشوند تا فرایندهای فرزند و استراتژی راهاندازی مجدد را مشخص کنند.
- درختان نظارتی (supervision trees) چیدمان سلسلهمراتبی ناظران و کارگران هستند که یک روش ساختاریافته برای ساخت برنامههای مقاوم در برابر خطا فراهم میکنند.
به طور خلاصه، فرایندها واحدهای اجرای پایه را فراهم میکنند، پایشها به فرایندها امکان میدهند یکدیگر را زیر نظر بگیرند، و ناظران سلسلهمراتبی از فرایندها را با سیاستهای راهاندازی مجدد تعریفشده هماهنگ میکنند. به طور یکپارچه، آنها ساخت برنامههای مقاوم Erlang خودترمیم را امکانپذیر میسازند.
نمونه برنامهنویسی تابعی
ویرایشیک تابع ارلنگ که از توابع بازگشتی برای شمارش تا ده استفاده میکند:
-module(count_to_ten).
-export([count_to_ten/0]).
count_to_ten() -> do_count(0).
do_count(10) -> 10;
do_count(N) -> do_count(N + 1).
الگوریتم اجرای فاکتوریل در ارلنگ:
-module(fact). % This is the file 'fact.erl', the module and the filename must match
-export([fac/1]). % This exports the function 'fac' of arity 1 (1 parameter, no type, no name)
fac(0) -> 1; % If 0, then return 1, otherwise (note the semicolon ; meaning 'else')
fac(N) when N> 0, is_integer(N) -> N * fac(N-1).
% Recursively determine, then return the result
% (note the period . meaning 'endif' or 'function end')
%% This function will crash if anything other than a nonnegative integer is given.
%% It illustrates the "Let it crash" philosophy of Erlang.
الگوریتم اجرای فیبوناچی در ارلنگ (توجه داشته باشید: این الگوریتم فقط برای نشان دادن نحوه نگارش ارلنگ است و از نظر زمانی بهینه نیست):
-module(fibonacci). % This is the file 'fibonacci.erl', the module and the filename must match
-export([fib/1]). % This exports the function 'fib' of arity 1
fib(0) -> 0; % If 0, then return 0, otherwise (note the semicolon ; meaning 'else')
fib(1) -> 1; % If 1, then return 1, otherwise
fib(N) when N> 1 -> fib(N - 1) + fib(N - 2).
مرتبسازی سریع در ارلنگ، با استفاده از لیست درک مطلب:
%% qsort:qsort(List)
%% Sort a list of items
-module(qsort). % This is the file 'qsort.erl'
-export([qsort/1]). % A function 'qsort' with 1 parameter is exported (no type, no name)
qsort([]) -> []; % If the list [] is empty, return an empty list (nothing to sort)
qsort([Pivot|Rest]) ->
% Compose recursively a list with 'Front' for all elements that should be before 'Pivot'
% then 'Pivot' then 'Back' for all elements that should be after 'Pivot'
qsort([Front || Front <- Rest, Front <Pivot]) ++
[Pivot] ++
qsort([Back || Back <- Rest, Back>= Pivot]).
در مثال بالا تابع فراخوانی بازگشتی مرتبسازی سریع تا زمانی که چیزی برای مرتبسازی باقی نمانده باشد ادامه پیدا میکند .
عبارت [Front || Front <- Rest, Front <Pivot] یک لیست درک است، به این معنی «ساخت یک لیست از عناصر Front بهطوریکه Front عضو Rest است، و Front کمتر از Pivot است.» ++ عملگر الحاق لیست است.
یک تابع مقایسه میتوان برای سازههای پیچیدهتر به خاطر خوانایی استفاده میشود.
کد زیر لیستها را بر اساس طول مرتب میکند:
% This is file 'listsort.erl' (the compiler is made this way)
-module(listsort).
% Export 'by_length' with 1 parameter (don't care about the type and name)
-export([by_length/1]).
by_length(Lists) -> % Use 'qsort/2' and provides an anonymous function as a parameter
qsort(Lists, fun(A,B) -> length(A) <length(B) end).
qsort([], _)-> []; % If list is empty, return an empty list (ignore the second parameter)
qsort([Pivot|Rest], Smaller) ->
% Partition list with 'Smaller' elements in front of 'Pivot' and not-'Smaller' elements
% after 'Pivot' and sort the sublists.
qsort([X || X <- Rest, Smaller(X,Pivot)], Smaller)
++ [Pivot] ++
qsort([Y || Y <- Rest, not(Smaller(Y, Pivot))], Smaller).
در اینجا، دوباره یک Pivot از اولین پارامتر داده شده به ()qsort گرفته شدهاست و نام لیست rest را Rest قرار دادهاست. توجه داشته باشید که بیان
[X || X <- Rest, Smaller(X,Pivot)]
تفاوتی با حالت زیر ندارد
[Front || Front <- Rest, Front <Pivot]
(در مثال قبل) به جز برای استفاده از یک تابع مقایسهای در آخرین بخش، صدا زدن"ساخت یک لیست از عناصر X
بهطوریکه X
یک عضو از Rest
است، و Smaller
درست میباشد." با Smaller
از پیش تعریف شده مانند
fun(A,B) -> length(A) <length(B) end
توجه داشته باشید تابع بینامی که Smaller
، در لیست پارامتر تعریف دوم qsort
هست را میتوان با نامی که در تابع اشاره شده نامید.
انواع داده
ویرایشIntegers
ویرایشاعداد صحیح به عنوان دنبالهای از اعداد اعشاری نوشته شدهاست، به عنوان مثال، ۱۲، ۱۲۳۷۵ و -۲۳٬۴۲۷ اعداد صحیح هستند. علم حساب اعداد صحیح دقیق و تنها محدود به حافظه موجود بر روی دستگاه است.
Atoms
ویرایشاتمها در یک برنامه برای نشان دادن ارزشهای متمایز استفاده میشود. آنها به صورت رشتهای از کاراکترهای الفبایی متوالی نوشته میشوند، اولین کاراکتر که حروف کوچک است. اتمها میتوانند شامل هر کاراکتر باشند اگر آنها در نقل قولهای محصور و یک کنوانسیون فرار وجود داشته باشد که اجازه میدهد هر کاراکتر در یک اتم استفاده شود.
Floats
ویرایشعداد ممیز شناور از IEEE 754 بیتی۶۴ استفاده میکند.
Reference
ویرایشمراجع نمادهای منحصر به فرد جهانی هستند که تنها ویژگی آنها این است که میتوان آنها را برای برابری مقایسه کرد.
نوع داده مرجع در زبان ارلنگ : در ارلنگ، یک مرجع یک عبارت منحصر به فرد است که برای شناسایی یک فرآیند یا منبع خاص در سیستم زمان اجرای ارلنگ ایجاد میشود. این منحصر به فرد بودن باعث میشود که مراجع را بتوان به طور ایمن در برنامهنویسی همزمان استفاده کرد، جایی که چندین فرآیند ممکن است همزمان در حال اجرا باشند. ایجاد مراجع مراجع با فراخوانی تابع درونی make_ref/0 تولید میشوند. هر فراخوانی از این تابع یک مرجع جدید تولید میکند که متمایز از همه مراجع دیگری است که در طول اجرای برنامه ایجاد شدهاند. این امر حیاتی است تا اطمینان حاصل شود که مراجع را میتوان به طور قابل اعتماد برای ردیابی منابع یا فرآیندها بدون خطر برخورد استفاده کرد.
ویژگیهای مراجع : منحصر به فرد بودن: هر مرجع تضمین میشود که در سراسر سیستم ارلنگ منحصر به فرد باشد. این بدان معناست که هیچ دو مرجعی هرگز برابر نخواهند بود، که آنها را برای تمایز بین موجودیتهای مختلف ایدهآل میکند. ثابت بودن: یک مرجع پس از ایجاد، قابل تغییر نیست. این ثابت بودن یک ویژگی مشترک در زبانهای برنامهنویسی تابعی مانند ارلنگ است. استفاده: مراجع اغلب در سناریوهای مربوط به ارتباطات آسنکرون استفاده میشوند، مانند زمانی که پیامها بین فرآیندها ارسال میشوند. آنها میتوانند به عنوان شناسههایی برای پاسخها یا ردیابی وضعیت عملیاتها عمل کنند.
Binaries
ویرایشدودویی دنبالهای از بایت است. باینری راه صرفه جویی در فضای ذخیرهسازی دادههای دودویی را ارائه میدهد.
Pids
ویرایشpid برای شناسایی فرایند کوتاه است. pid توسط ارقام ابتدایی ارلنگ ایجاد میشود.
Ports
ویرایشPorts برای برقراری ارتباط با دنیای خارج استفاده میشود. پورتها با function-built-in open_port ایجاد میشوند. پیامها را میتوان به پورتها ارسال و دریافت کرد، اما این پیامها باید به اصطلاح «پروتکل پورت» مطابقت داشته باشند.
Funs
ویرایشFuns تابع بستهاست. Funs توسط عبارات فرم ایجاد میشود: Fun(...) -> … end
Tuples
ویرایشTupels ظروف برای تعداد ثابت از انواع داده ارلنگ هستند. نحو {D1 , D2, … ,Dn} یک تابع را نشان میدهد که استدلال آن D1, D2, … ,Dn است. استدلال میتواند نوع دادههای اولیه یا انواع دادههای ترکیب باشد. هر عنصر یک دوره زمانی میتواند در زمان ثابت مشاهده شود.
Lists
ویرایشلیستها ظروف برای تعداد متغیری از انواع داده Erlang هستند. نحو [Dh | Dt] یک لیست را نشان میدهد که اولین عنصر آن Dh است و عناصر باقیمانده آن Dt است. نحو [] یک لیست خالی را نشان میدهد. نحو [D1، D2، ..، Dn] کوتاه است برای [D1 | [D2 | .. | [Dn | []]]]. اولین عنصر از یک لیست در زمان ثابت قابل دسترسی است. اولین عنصر از لیست، سر لیست است. باقیمانده از یک لیست زمانی که سر آن حذف شدهاست، دم لیست است.
Maps
ویرایشنقشهها دارای تعداد متغیری از ارتباطات کلیدی ارزش هستند. نحو به این صورت # {Key1 => Value1، …، KeyN => ValueN} است.
Strings
ویرایشرشتهها مابین نقل قول دوتایی نوشته میشوند. این یک نحو جالب برای نمایش دنبالهای از کدهای اسکی یا لیستی از کارکترها میباشد؛ بنابراین، به عنوان مثال، رشته "CAT" به صورت [۹۹٬۹۷٬۱۱۶] کوتاه میشود. این پشتیبانی جزئی برای رشته Unicode است.
Records
ویرایشسوابق یک راه مناسب برای ارتباط یک برچسب با هر یک از عناصر در یک تاپل فراهم میکند. این موضوع اجازه میدهد تا به یک عنصر از یک تاپل با نام و نه با موقعیت اشاره کرد. یک پیش کامپایلر طول میکشد؛ رکورد، تعریف و جایگزین آن با مرجع تاپل مناسب شود.
بارگذاری کد و ماژولهای جدید
ویرایشارلنگ از بروزرسانی برنامههایی با سطح زبان پویا پشتیبانی میکند. برای اجرای این، کد به عنوان یک واحد «ماژول» بارگذاری و مدیریت میشود؛ ماژول یک واحد تلفیقی است. سیستم میتواند همزمان دو نسخه از یک ماژول را در حافظه نگه دارد و فرایندها میتوانند همزمان هر یک از کدها را اجرا کنند. به نسخهها با نسخههای جدید و قدیمی مراجعه میشود. فرایندها تا زمانی که یک تماس خارجی به ماژول آن ایجاد نشود به نسخه جدید تبدیل نمیشوند.
یک مثال از مکانیزم بارگیری کد:
%% A process whose only job is to keep a counter.
%% First version
-module(counter).
-export([start/0, codeswitch/1]).
start() -> loop(0).
loop(Sum) ->
receive
{increment, Count} ->
loop(Sum+Count);
{counter, Pid} ->
Pid ! {counter, Sum},
loop(Sum);
code_switch ->
?MODULE:codeswitch(Sum)
% Force the use of 'codeswitch/1' from the latest MODULE version
end.
codeswitch(Sum) -> loop(Sum).
برای نسخه دوم، ما امکان اضافه کردن شمارش به صفر را اضافه میکنیم.
%% Second version
-module(counter).
-export([start/0, codeswitch/1]).
start() -> loop(0).
loop(Sum) ->
receive
{increment, Count} ->
loop(Sum+Count);
reset ->
loop(0);
{counter, Pid} ->
Pid ! {counter, Sum},
loop(Sum);
code_switch ->
?MODULE:codeswitch(Sum)
end.
codeswitch(Sum) -> loop(Sum).
منابع
ویرایش- ↑ "Release 27.1.2". 17 اکتبر 2024. Retrieved 18 October 2024.
- ↑ Wikipedia contributors, "Erlang (programming language)," Wikipedia, The Free Encyclopedia, http://en.wiki.x.io/w/index.php?title=Erlang_(programming_language)&oldid=417616995 (accessed March 10, 2011).
- ↑ Wikipedia contributors, "Erlang (programming language)," Wikipedia, The Free Encyclopedia, https://en.wiki.x.io/wiki/Erlang_(programming_language)
- ↑ «Processes — Erlang System Documentation v27.0.1». www.erlang.org. دریافتشده در ۲۰۲۴-۰۸-۱۱.