برنامه نویسی واکنشی
در رایانش ، برنامه نویسی واکنشی یک الگوی برنامه نویسی اعلانی است که مربوط به جریان داده ها و انتشار تغییرات است. "با استفاده از این الگو ، می توان جریان داده های" ساکن (به عنوان مثال ، آرایه ها) یا داده های پویا (به عنوان مثال ، ساطع کننده های رویداد) را با سهولت بیان کرد و همچنین اعلام کرد که وابستگی استنباط شده در "مدل اجرایی" مرتبط وجود دارد ، که انتشار اتوماتیک جریان داده های تغییر یافته را تسهیل می کند .
به عنوان مثال ، در یک برنامه‌نویسی دستوری "،" formula_1 به این معنی است که حاصل formula_2 در همان لحظه‌ی محاسبه عبارت به formula_3 اختصاص داده میشود و بعداً مقادیر formula_4 و formula_5 را می توان بدون هیچ تاثیری بر مقدار formula_3 تغییر داد . از طرف دیگر ، در برنامه نویسی "واکنشی ،" هر زمان که مقادیر formula_4 یا formula_5 تغییر کند مقدار formula_3 به صورت خودکار تغییر میکند ، بدون اینکه برنامه مجبور به اجرای دوباره‌ی جداگانه دستور formula_1 باشد تا بتواند مقدار کنونی مقدار formula_3 را بدست آورد.مثال دیگر ، زبان توصیف سخت افزار مانند Verilog است ، جایی که برنامه نویسی واکنشی باعث می شود تغییرات هنگام انتشار از طریق مدارها مدل شوند.
برنامه نویسی واکنشی به عنوان روشی برای ساده سازی ایجاد رابط های کاربری و انیمیشن تقریباً بلا درنگ پیشنهاد شده است.
به عنوان مثال ، در مدل-نما-کنترل‌گر (MVC) ، برنامه نویسی واکنشی می تواند تغییرات در "مدل" زیرین را به صورت خودکار در رابط گرافیکی مرتبط منعکس کند.
چندین روش محبوب در ایجاد زبان‌های برنامه‌نویسی واکنشی به کار گرفته شده‌اند. مشخصات زبان‌های اختصاصی که مختص محدودیت‌های دامنه مختلف هستند. چنین محدودیت‌هایی معمولاً به شکل بلادرنگ ،محاسبات تعبیه‌شده یا توصیف سخت‌افزار مشخص می‌شوند. رویکرد دیگر شامل توصیف زبان‌های هدف عمومی است که شامل پشتیبانی از واکنش‌پذیری است. رویکردهای دیگر در تعریف، و استفاده از کتابخانه‌های برنامه‌نویسی، یا زبان‌های خاص دامنه تعبیه‌شده، که امکان واکنش‌پذیری در کنار یا روی زبان برنامه‌نویسی را فراهم می‌کنند، بیان می‌شوند. مشخصات و استفاده از این رویکردهای مختلف منجر به تبادل قابلیت زبان می‌شود. به طور کلی، هر چه یک زبان محدودتر باشد، کامپایلرهای مرتبط و ابزارهای تجزیه و تحلیل آن بیشتر قادر به اطلاع‌رسانی به توسعه دهندگان هستند (به عنوان مثال، در انجام تجزیه و تحلیل برای اینکه آیا برنامه‌ها قادر به اجرا در زمان واقعی هستند یا خیر). تبادل عملکردی در ویژگی ممکن است منجر به بدتر شدن کاربرد کلی یک زبان شود. ​
برنامه نویسی واکنشی مفاهیم و انواع مختلفی دارد که می توانیم آنها را به موراد زیر تقسیم کنیم:
زمان های اجرای زبان برنامه نویسی واکنشی با گرافی نشان داده می شوند که وابستگی ها را در میان مقادیر واکنشی درگیر مشخص می کند. در چنین نموداری ، "گره ها نشان دهنده عمل" محاسبه هستند و لبه ها روابط وابستگی مدل "لبه ها را مدل میکنند." همچین زمان اجرایی از نمودار ذکر شده استفاده می کند تا به آن کمک کند وقتی مقدار ورودی مربوطه تغییر میکند و محاسبات باید دوباره اجرا شوند، کنترل کند.
متداول ترین روش های انتشار داده :
در سطح پیاده سازی ، "واکنش رویداد" شامل انتشار از طریق اطلاعات نمودار است که نشان دهنده وجود تغییر است. در نتیجه ، محاسباتی که تحت تأثیر چنین تغییری قرار می گیرند منسوخ می شوند و باید برای اجرای مجدد مشخص شوند. چنین محاسباتی معمولاً با بسته شدن انتقالی تغییر در منبع مرتبط آن مشخص می شود. "سپس انتشار تغییر" ممکن است منجر به بروزرسانی مقدار نشست نمودار شود.
اطلاعات منتشر شده از نمودار می تواند تشکیل شده از حالت کامل یک گره باشد ، یعنی نتیجه محاسبات گره درگیر. در این حالت ، خروجی قبلی گره نادیده گرفته می شود. یک روش دیگر شامل "تکثیر دلتا" یعنی "تکثیر تغییر فزاینده است" . در این حالت ، اطلاعات در امتداد "لبه های" نمودار تکثیر می شوند ، که فقط شامل "دلتا هستند" و نحوه تغییر گره قبلی را توصیف می کنند. این رویکرد به ویژه هنگامی مهم است که "گره ها" مقدار زیادی از "داده های حالت(state data) را در خود" نگه می دارند که در غیر اینصورت هزینه محاسبه مجدد آنها از ابتدا گران خواهد بود.
"انتشار دلتا" اساساً یک بهینه سازی است که به طور گسترده از طریق رشته محاسبات افزایشی مورد مطالعه قرار گرفته است ، که روش آن نیاز به رضایت از زمان اجرا که شامل مشکل بروزرسانی میشود، است. این مشکل با استفاده از نهادهای پایگاه داده ، که مسئول نگهداری تغییر داده های تغییر داده هستند ،شناخته میشود.
یکی دیگر از بهینه سازی های متداول ، استفاده از "انباشت تغییر یکپارچه" و "انتشار دسته ای است" . چنین راه حلی می تواند سریعتر باشد زیرا ارتباط بین گره های درگیر را کاهش می دهد. سپس می توان از استراتژی های بهینه سازی استفاده کرد که راجع به ماهیت تغییرات موجود توضیح میدهند و بر این اساس تغییرات ایجاد می شوند. به عنوان مثال دو تغییر در دسته می تواند یکدیگر را لغو کند ، و بنابراین ، به سادگی نادیده گرفته شوند. روش موجود دیگر ، به عنوان "انتشار اعلان بی اعتباری" شناخته می شود. این رویکرد باعث می شود که گره هایی که ورودی نامعتبر دارند ، به روزرسانی شوند و در نتیجه منجر به به روزرسانی خروجی های خودشان می شوند.
"در ساخت نمودار وابستگی" دو روش اصلی وجود دارد:
هنگام تکثیر تغییرات ، می توان دستورات تکثیر را به طوری انتخاب کرد که مقدار یک عبارت نتیجه طبیعی برنامه منبع نباشد. ما می توانیم این مسئله را با یک مثال به راحتی نشان دهیم. فرض کنید codice_1 یک مقدار واکنشی است که هر ثانیه تغییر می کند تا زمان فعلی را نشان دهد (در واحد ثانیه). این عبارت را در نظر بگیرید:
چون codice_2 باید همیشه بزرگتر از codice_1 ، این عبارت باید همیشه با مقدارtrue ارزیابی شود. متأسفانه ، این می تواند به ترتیب ارزیابی بستگی داشته باشد. ,وقتی codice_1 نغییر میکند ، دو عبارت باید به روز شوند: codice_5 و شرط. اگر مورد اول قبل از مورد دوم ارزیابی شود ، این نامتغیرثابت باقی خواهد ماند. اگر ، ابتدا شرط با استفاده از مقدار قدیمی codice_2 و مقدار جدید codice_1 ، ابتدا به روز شود ، این عبارت به یک مقدار نادرست ارزیابی می شود. به این "اشکال(Glitch) گفته می شود" .
برخی از زبانهای واکنشی بدون اشکال هستند و این ویژگی را اثبات می کنند این امر معمولاً با مرتب سازی توپولوژیکی عبارات و به روزرسانی مقادیر به ترتیب توپولوژیکی حاصل می شود. با این حال ، این می تواند پیامدهای عملکردی مانند تأخیر در تحویل مقادیر (به دلیل ترتیب انتشار) داشته باشد. بنابراین ، در بعضی موارد ، زبانهای واکنشی اشکالات را مجاز می دانند و توسعه دهندگان باید از این احتمال که ممکن است مقادیر به طور موقت با منبع برنامه مطابقت نداشته باشند آگاه باشند و برخی عبارات ممکن است چندین بار ارزیابی شوند (به عنوان مثال codice_8 ممکن است دو بار ارزیابی شود: یک بار با رسیدن مقدار جدید codice_1 ، و یک بار دیگر codice_2 به روزرسانی t).
مرتب سازی توپولوژیکی وابستگی ها به نمودار دایره ای چرخشی (DAG) بودن نمودار وابستگی بستگی دارد. در عمل ، یک برنامه ممکن است یک نمودار وابستگی تعریف کند که دارای چرخه باشد. معمولاً ، زبانهای برنامه نویسی واکنشی با قرار دادن مقداری عنصر در امتداد "لبه پشتی" انتظار دارند چنین چرخه هایی "شکسته شود" تا اجازه دهد به روزرسانی واکنشی خاتمه یابد. به طور معمول ، زبان ها عملیاتی مانند codice_11 ارائه می دهند که توسط مکانیزم به روزرسانی برای این منظور استفاده می شود ، زیرا codice_11 بیانگر این است که مواردی که در ادامه مطرح میشود باید در "مرحله بعدی" ارزیابی شوند ( و اجازه می دهد ارزیابی فعلی خاتمه یابد).
زبانهای واکنشی معمولاً فرض می کنند که عبارات آنها کاملاً کاربردی هستند . این به یک مکانیزم بروزرسانی اجازه می دهد تا سفارشات مختلفی را که برای انجام آنها به روز می شود انتخاب کند و سفارش خاص را بدون مشخص بگذارد (در نتیجه امکان بهینه سازی را فراهم می کند). با این وجود ، هنگامی که یک زبان واکنشی در یک زبان برنامه نویسی با حالت تعبیه شده است ، انجام برنامه های تغییر پذیر برای برنامه نویسان امکان پذیر است. نحوه بهبود این تعامل مشکلی است که همچنان حل نشده است.
در بعضی موارد ، ممکن است راه حل های جزئی اصولی وجود داشته باشد. دو راه حل از این دست عبارتند از:
در برخی از زبانهای واکنشی ، نمودار وابستگی ها "ثابت است" ، یعنی نمودار در طول اجرای برنامه ثابت است. در زبان های دیگر ، نمودار می تواند "پویا باشد" ، یعنی با اجرای برنامه می تواند تغییر کند. برای یک مثال ساده ، این مثال گویا را در نظر بگیرید (جایی که codice_1 مقدار واکنشی است):در هر ثانیه ، مقدار این عبارت به یک عبارت واکنشی متفاوت تغییر می کند که codice_14 به آن بستگی دارد. بنابراین نمودار وابستگی ها در هر ثانیه به روز می شود.
اجازه دادن به آپدیت شدن پویا به وابستگی ها ، قدرت توضیح قابل توجهی را فراهم می کند (به عنوان مثال ، وابستگی های پویا به طور معمول در برنامه های رابط کاربر گرافیکی (GUI) رخ می دهد). با این حال ، موتور به روزرسانی واکنشی باید تصمیم بگیرد که هر بار عبارات را بازسازی کند یا گره یک عبارت را بسازد اما غیرفعال نگه دارد. در حالت دوم ، باید اطمینان حاصل شود زمانی که قرار نیست از عبارت مربوط به گره استفاده شود، آنها در محاسبه شرکت نکنند.
زبانهای برنامه نویسی واکنشی می توانند از زبانهای کاملاً واضح که جریانهای داده با استفاده از فلش (arrow) تنظیم می شوند ، تا در جایی که جریان داده ها از سازه های زبان که شبیه برنامه های ضروری یا کاربردی است ، متغیر باشند. به عنوان مثال ، در یک برنامه نویسی واکنش پذیر عملکردی (FRP) که به طور ضمنی لیفت شده است ، یک فراخوانی تابع ممکن است به طور ضمنی باعث ایجاد یک گره در نمودار جریان داده شود. کتابخانه های برنامه نویسی واکنشی برای زبانهای پویا (مانند کتابخانه های "Lisp" Cells و Python "Trellis") می توانند یک نمودار وابستگی از تجزیه و تحلیل زمان اجرا از مقادیر خوانده شده در هنگام اجرای یک تابع ایجاد کنند ، که به مشخصات جریان داده اجازه می دهد تا بصورت و پویا باشند.
گاهی اوقات اصطلاح "برنامه نویسی واکنش پذیر" به سطح معماری مهندسی نرم‌افزار اشاره دارد ، جایی که گره های منفرد در نمودار جریان داده ها برنامه های معمولی هستند که با یکدیگر ارتباط برقرار می کنند.
برنامه نویسی واکنشی می تواند کاملاً ایستا باشد در جایی که جریان داده ها به صورت استاتیک تنظیم شده باشد ، یا در جایی که جریان داده می تواند در حین اجرای یک برنامه تغییر کند ، پویا باشد.
استفاده از سوئیچ های داده در نمودار جریان داده می تواند تا حدی نمودار جریان داده ایستا را پویا نشان دهد و تمایز را کمی تار کند. با این حال ، برنامه نویسی واکنشی پویا واقعی می تواند از برنامه نویسی دستوری برای بازسازی نمودار جریان داده استفاده کند.
میتوان گفت برنامه نویسی واکنشی جزو زبان های با مرتبه بالاتر است اگر این ایده را پشتیبانی کند که از جریان داده می تواند برای ساخت سایر جریان های داده استفاده کرد. یعنی مقدار حاصل از جریان داده ، نمودار جریان داده دیگری است که با استفاده از همان مدل ارزیابی اول اجرا می شود.
در حالت ایده‌آل ، همه تغییرات داده بلافاصله منتشر می شوند ، اما در عمل نمی توان به این امر اطمینان داشت. در عوض ممکن است لازم باشد که به بخشهای مختلف نمودار جریان داده ، اولویتهای ارزیابی متفاوتی داده شود. این را می توان برنامه نویسی واکنشی متمایز نامید.
به عنوان مثال ، در یک پردازنده کلمه، علامت گذاری اشتباهات املایی کاملاً با درج کاراکترها هماهنگ نیست. در اینجا می توان به طور بالقوه از برنامه ریزی واکنشی متمایز استفاده کرد تا اولویت کمتری به هجی کننده بدهد ، و در عین حال با وجود نگه داشتن این عملیات، جریانهای داده دیگر را اجرا کند.
با این حال ، چنین تمایزی پیچیدگی طراحی اضافی را به همراه دارد. به عنوان مثال ، تصمیم گیری در مورد چگونگی تعریف مناطق مختلف جریان داده و نحوه مدیریت عبور از رویداد بین مناطق مختلف جریان داده یکی از این پیچیدگی هاست.
ارزیابی برنامه های واکنشی لزوماً براساس چگونگی ارزیابی زبان های برنامه نویسی مبتنی بر پشته نیست. در عوض ، هنگامی که برخی از داده ها تغییر می کنند ، تغییر به تمام داده هایی که از داده هایی که تغییر داده شده اند به طور جزئی یا کامل استخراج می شوند ، انتشار می یابد. این تکثیر تغییر را می توان از راه های مختلفی به دست آورد ، که شاید طبیعی ترین راه یک طرح باطل / تنبل-تجدید(invalidate/lazy-revalidate ) ارزیابی مجدد باشد.
انتشاز تغییر با استفاده از پشته میتواند به راحتی مشکل ساز شود.اگر ساختار داده شکل خاصی داشته باشد به دلیل پیچیدگی بروزرسانی نمایی بالقوه است. یکی از این اشکال را می توان به عنوان "شکل الماس های مکرر" توصیف کرد ، و دارای ساختار زیر است: A → B → A ، A → C → A ، جایی که n = 1،2. . . این مشکل می تواند تنها با انتشار اعتبار نامعتبر هنگامی که برخی از داده ها قبلاً اعتبار ندارند ، برطرف شود و بعداً با استفاده از ارزیابی تنبل ، داده ها مجدداً تأیید شوند.
یک مشکل ذاتی برای برنامه نویسی واکنشی این است که بیشتر محاسباتی که در یک زبان برنامه نویسی معمولی ارزیابی و فراموش می شوند ، باید در حافظه به عنوان ساختارهای داده نشان داده شوند. این به طور بالقوه می تواند باعث شود برنامه نویسی واکنشی را به شدت حافظه مصرف کند. با این حال ، تحقیق در مورد آنچه که "کاهش" نامیده می شود ، می تواند به طور بالقوه بر این مشکل غلبه کند.
از طرف دیگر ، برنامه نویسی واکنشی نوعی از آنچه می توان به عنوان "موازی سازی صریح" توصیف کرداست و بنابراین می تواند برای استفاده از قدرت سخت افزار موازی مفید باشد.
برنامه نویسی واکنش پذیر شباهت های اصلی با الگوی مشاهده گر که معمولاً در برنامه نویسی شی گرا استفاده می شود، دارد. با این حال ، ادغام مفاهیم جریان داده در زبان برنامه نویسی بیان آنها را آسان تر می کند و بنابراین می تواند دانه بندی نمودار جریان داده ها را افزایش دهد. به عنوان مثال ، الگوی مشاهدهگر معمولاً جریان داده ها را بین کل اشیا / / کلاسها توصیف می کند ، در حالی که برنامه نویسی واکنشی شی گرا می تواند اعضای اشیا / / کلاسها را هدف قرار دهد.
می توان برنامه نویسی واکنشی را با برنامه دستوری معمولی ترکیب کرد. در چنین الگویی ، برنامه های دستوری بر ساختار داده های واکنش پذیر عمل می کنند. چنین تنظیماتی مشابه برنامه های دستوری محدودیت است . با این حال ، در حالی که برنامه نویسی دستوری محدودیت های دو جهته را کنترل می کند ، اما برنامه نویسی واکنشی، محدودیت های جریان داده یک طرفه را مدیریت می کند.
برنامه نویسی واکنشی شی گرا (OORP) ترکیبی از برنامه نویسی شی گرا و برنامه نویسی واکنشی است. شاید طبیعی ترین راه برای ایجاد چنین ترکیبی به شرح زیر باشد: به جای روش ها و زمینه ها ، اشیا "واکنشی" دارند که به طور خودکار مجدداً ارزیابی می شوند ، وقتی که سایر واکنش هایی که به آن بستگی دارند ، اصلاح شده باشند.
اگر یک زبان OORP روش های دستوری خود را حفظ کند ، در گروه برنامه نویسی واکنشی دستوری قرار می گیرد.
برنامه نویسی واکنش پذیر عملکردی (FRP) یک الگوی برنامه نویسی برای برنامه نویسی واکنشی بر روی برنامه نویسی عملکردی است .
از بازیگران برای طراحی سیستمهای واکنشی ، اغلب در ترکیب با برنامه نویسی واکنش کاربردی (FRP) برای توسعه سیستمهای واکنشی توزیع استفاده شده است.
دسته نسبتاً جدیدی از زبان های برنامه نویسی از قید ها (قوانین) به عنوان مفهوم اصلی برنامه نویسی استفاده می کنند. این شام ل واکنش به حوادث است که همه محدودیت ها را حل میکند. این نه تنها واکنش های مبتنی بر رویداد را تسهیل می کند ، بلکه باعث می شود برنامه های واکنشی در درستی نرم‌افزار نقش داشته باشند. یک مثال از زبان برنامه نویسی واکنش پذیر مبتنی بر قاعده ، Ampersand است که در جبر رابطه ایجاد شده است.