กลับไปหน้าบทความ

อ่าน 7 นาที

การเขียนโปรแกรมเชิงตอบสนอง

ในด้านการคำนวณการเขียนโปรแกรมเชิงปฏิกิริยา (Reactive Programming)เป็นกระบวนทัศน์การเขียนโปรแกรมเชิงประกาศ ที่เกี่ยวข้องกับกระแสข้อมูลและการแพร่กระจายของการเปลี่ยนแปลง...

การเขียนโปรแกรมเชิงตอบสนอง

ในด้านการคำนวณการเขียนโปรแกรมเชิงปฏิกิริยา (Reactive Programming)เป็นกระบวนทัศน์การเขียนโปรแกรมเชิงประกาศ ที่เกี่ยวข้องกับกระแสข้อมูลและการแพร่กระจายของการเปลี่ยนแปลง ด้วยกระบวนทัศน์นี้ ทำให้สามารถแสดงกระแสข้อมูลแบบคงที่ (เช่นอาร์เรย์ ) หรือแบบไดนามิก (เช่นตัวปล่อยเหตุการณ์ ) ได้อย่างง่ายดาย และยังสามารถสื่อสารถึงการพึ่งพาที่อนุมานได้ภายในแบบจำลอง การดำเนินการที่เกี่ยวข้องซึ่งอำนวยความสะดวกในการแพร่กระจายกระแสข้อมูลที่ เปลี่ยนแปลงโดยอัตโนมัติ [ 1 ] [ 2 ]

ตัวอย่างเช่น ในการเขียนโปรแกรมเชิงคำa := b + cสั่ง หมายความว่าaกำลังถูกกำหนดค่าผลลัพธ์ของb + cในขณะที่นิพจน์ถูกประเมิน และในภายหลัง ค่าของbและcสามารถเปลี่ยนแปลงได้โดยไม่มีผลต่อค่าของaในทางตรงกันข้าม ใน การเขียนโปรแกรม เชิงปฏิกิริยาค่าของaจะได้รับการอัปเดตโดยอัตโนมัติทุกครั้งที่ค่าของbหรือcเปลี่ยนแปลง โดยที่โปรแกรมไม่จำเป็นต้องระบุคำสั่งใหม่a := b + cเพื่อกำหนดค่าของ อีกครั้งaอย่าง ชัดเจน

var b = 1 var c = 2 var a = b + c b = 10 console.log ( a ) // 3 (ไม่ใช่ 12 เพราะ " =" ไม่ใช่ตัวดำเนินการกำหนดค่าแบบตอบสนอง)// ลองนึกภาพว่ามีตัวดำเนินการพิเศษ "$=" ที่เปลี่ยนค่าของตัวแปร (เรียกใช้โค้ดทางด้านขวาของตัวดำเนินการและกำหนดผลลัพธ์ให้กับตัวแปรทางด้านซ้าย) เมื่อใดก็ตามที่มีการกำหนดค่าเริ่มต้นอย่างชัดเจน และเมื่อตัวแปรที่อ้างอิง (ทางด้านขวาของตัวดำเนินการ) เปลี่ยนแปลงvar b = 1 var c = 2 var a $ = b + c b = 10 console.log ( a ) // 12

อีกตัวอย่างหนึ่งคือภาษาสำหรับการอธิบายฮาร์ดแวร์เช่นVerilogซึ่งการเขียนโปรแกรมแบบตอบสนอง (reactive programming) ช่วยให้สามารถจำลองการเปลี่ยนแปลงขณะที่มันแพร่กระจายไปทั่ววงจรได้

การเขียนโปรแกรมเชิงตอบสนอง (Reactive programming) ได้รับการเสนอให้เป็นวิธีการหนึ่งในการทำให้การสร้างส่วนติดต่อผู้ใช้ แบบโต้ตอบ และ การสร้าง ภาพเคลื่อนไหว แบบเรี ยลไทม์ ง่ายขึ้น

ตัวอย่างเช่น ใน สถาปัตยกรรม โมเดล-วิว-คอนโทรลเลอร์ (MVC) การเขียนโปรแกรมแบบตอบสนองสามารถอำนวยความสะดวกให้การเปลี่ยนแปลงในโมเดลพื้นฐานสะท้อนให้เห็นโดยอัตโนมัติในวิว ที่เกี่ยวข้อง [ 3 ]

แนวทางการสร้างภาษาโปรแกรมเชิงตอบสนอง

มีแนวทางที่เป็นที่นิยมหลายวิธีในการสร้างภาษาโปรแกรมเชิงตอบสนอง (reactive programming languages) แนวทางหนึ่งคือการกำหนด ภาษา เฉพาะที่ใช้กับข้อจำกัดต่างๆ ในโดเมนข้อจำกัดเหล่านี้มักเกี่ยวข้องกับระบบเรียลไทม์ การประมวลผลแบบฝังตัว หรือคำอธิบายฮาร์ดแวร์ อีกแนวทางหนึ่งคือการกำหนด ภาษา อเนกประสงค์ที่รองรับการทำงานเชิงตอบสนอง แนวทางอื่นๆ คือการกำหนดและการใช้ไลบรารี การเขียนโปรแกรม หรือ ภาษาเฉพาะโดเมนแบบ ฝังตัว (embedded domain-specific languages ) ที่ช่วยให้การทำงานเชิงตอบสนองเกิดขึ้นได้ควบคู่ไปกับหรืออยู่เหนือภาษาโปรแกรม การกำหนดและการใช้แนวทางต่างๆ เหล่านี้ส่งผลให้เกิดการแลกเปลี่ยนความสามารถ ของภาษา โดยทั่วไปแล้ว ยิ่งภาษามีข้อจำกัดมากเท่าใดคอมไพเลอร์และเครื่องมือวิเคราะห์การเขียนโปรแกรม ที่เกี่ยวข้องก็จะยิ่ง สามารถให้ข้อมูลแก่ผู้พัฒนาได้มากขึ้นเท่านั้น (เช่น ในการวิเคราะห์ว่าโปรแกรมสามารถทำงานได้จริงในเวลาจริงหรือไม่) การแลกเปลี่ยนฟังก์ชันการทำงานในด้านความเฉพาะเจาะจงอาจส่งผลให้ความสามารถในการใช้งานทั่วไปของภาษาลดลง

แบบจำลองการเขียนโปรแกรมและความหมาย

การเขียนโปรแกรมเชิงตอบสนอง (Reactive Programming) มีรูปแบบและ ความหมายที่หลากหลายซึ่งสามารถแบ่งออกอย่างคร่าวๆ ได้เป็นสามมิติ:

เทคนิคการนำไปใช้และความท้าทาย

สาระสำคัญของการนำไปปฏิบัติ

ระบบรันไทม์ของภาษาโปรแกรมเชิงปฏิกิริยาจะถูกแสดงด้วยกราฟที่ระบุความสัมพันธ์ระหว่างค่าเชิงปฏิกิริยาที่เกี่ยวข้อง ในกราฟดังกล่าวโหนดแสดงถึงการกระทำของการคำนวณ และขอบ แสดง ถึงความสัมพันธ์ของการพึ่งพา ระบบรันไทม์ดังกล่าวใช้กราฟนี้เพื่อช่วยในการติดตามการคำนวณต่างๆ ที่ต้องดำเนินการใหม่ทุกครั้งที่ค่าอินพุตที่เกี่ยวข้องเปลี่ยนแปลง

อัลกอริทึมการแพร่กระจายการเปลี่ยนแปลง

วิธีการแพร่กระจายข้อมูลที่พบได้บ่อยที่สุด ได้แก่:

  • แบบดึง (Pull) – ผู้บริโภคคุณค่ามีความกระตือรือร้นกล่าวคือ จะสอบถามแหล่งข้อมูลที่สังเกตได้อย่างสม่ำเสมอเพื่อหาคุณค่า และตอบสนองเมื่อใดก็ตามที่มีคุณค่าที่เกี่ยวข้อง การตรวจสอบเหตุการณ์หรือการเปลี่ยนแปลงของคุณค่าอย่างสม่ำเสมอเช่นนี้ มักเรียกว่าการสำรวจ (Polling )
  • พุช (Push) – ผู้รับจะได้รับค่าจากแหล่งที่มาเมื่อใดก็ตามที่ค่านั้นพร้อมใช้งาน ค่าเหล่านี้มีความสมบูรณ์ในตัวเอง เช่น มีข้อมูลที่จำเป็นทั้งหมด และผู้รับไม่จำเป็นต้องสอบถามข้อมูลเพิ่มเติมอีก
  • การสื่อสาร แบบพุช-พูล – ผู้รับข้อมูลจะได้รับการแจ้งเตือนการเปลี่ยนแปลงซึ่งเป็นคำอธิบายสั้นๆ เกี่ยวกับการเปลี่ยนแปลง เช่น "ค่าบางอย่างเปลี่ยนแปลงไป": นี่คือ ส่วนของ การพุชอย่างไรก็ตาม การแจ้งเตือนนี้ไม่ได้มีข้อมูลที่จำเป็นทั้งหมด (ซึ่งหมายความว่ามันไม่ได้มีค่าจริง) ดังนั้นผู้รับข้อมูลจึงต้องสอบถามข้อมูลเพิ่มเติม (ค่าเฉพาะ) จากแหล่งข้อมูลหลังจากได้รับการแจ้งเตือนแล้ว: นี่คือ ส่วนของ การพูลวิธีนี้มักใช้เมื่อมีข้อมูลจำนวนมากที่ผู้รับข้อมูลอาจสนใจ ดังนั้น เพื่อลดปริมาณงานและความหน่วง จึงมีการส่งการแจ้งเตือนที่มีขนาดเล็กเท่านั้น จากนั้นผู้รับข้อมูลที่ต้องการข้อมูลเพิ่มเติมจะร้องขอข้อมูลเฉพาะนั้น วิธีการนี้ยังมีข้อเสียคือ แหล่งข้อมูลอาจถูกประมวลผลด้วยคำขอข้อมูลเพิ่มเติมจำนวนมากหลังจากส่งการแจ้งเตือนแล้ว

ต้องกดอะไร?

ในระดับการนำไปใช้การตอบสนองต่อเหตุการณ์ประกอบด้วยการแพร่กระจายข้อมูลในกราฟ ซึ่งบ่งบอกถึงการเปลี่ยนแปลงที่เกิดขึ้น ดังนั้น การคำนวณที่ได้รับผลกระทบจากการเปลี่ยนแปลงดังกล่าวจึงล้าสมัยและต้องถูกทำเครื่องหมายเพื่อดำเนินการใหม่ โดยปกติแล้ว การคำนวณดังกล่าวจะถูกกำหนดลักษณะโดยการปิดแบบส่งต่อของการเปลี่ยนแปลง (เช่น ชุดของการพึ่งพาแบบส่งต่อทั้งหมดที่แหล่งที่มาส่งผลกระทบ) ในแหล่งที่มาที่เกี่ยวข้องการแพร่กระจายของการเปลี่ยนแปลงอาจนำไปสู่การอัปเดตค่าของปลายทาง ในกราฟ ได้

ข้อมูลที่ส่งต่อในกราฟอาจประกอบด้วยสถานะที่สมบูรณ์ของโหนด เช่น ผลลัพธ์การคำนวณของโหนดที่เกี่ยวข้อง ในกรณีเช่นนี้ ผลลัพธ์ก่อนหน้าของโหนดจะถูกละเลย อีกวิธีหนึ่งคือการส่งต่อแบบเดลต้าหรือการแพร่กระจายการเปลี่ยนแปลงแบบเพิ่มขึ้น ในกรณีนี้ ข้อมูลจะถูกส่งต่อตาม ขอบของกราฟซึ่งประกอบด้วย ค่า เดลต้าที่อธิบายว่าโหนดก่อนหน้าเปลี่ยนแปลงไปอย่างไร วิธีนี้มีความสำคัญอย่างยิ่งเมื่อโหนด มี ข้อมูลสถานะจำนวนมากซึ่งหากไม่ใช้วิธีนี้จะต้องเสียค่าใช้จ่ายสูงในการคำนวณใหม่ทั้งหมด

การแพร่กระจายเดลต้า (Delta propagation)โดยพื้นฐานแล้วเป็นการปรับปรุงประสิทธิภาพที่ได้รับการศึกษาอย่างกว้างขวางผ่านสาขาวิชาการคำนวณแบบเพิ่มทีละน้อย (incremental computing ) ซึ่งวิธีการนี้ต้องการความพึงพอใจในระหว่างการทำงานที่เกี่ยวข้องกับปัญหาการอัปเดตมุมมอง (view-update problem ) ปัญหานี้เป็นที่รู้จักกันดีในเรื่องการใช้เอนทิตีฐานข้อมูล (database entities) ซึ่งมีหน้าที่ในการบำรุงรักษาการเปลี่ยนแปลงมุมมองข้อมูล

อีกหนึ่งวิธีการเพิ่มประสิทธิภาพที่พบได้ทั่วไปคือ การใช้การสะสมการเปลี่ยนแปลงแบบเอกภาคและการแพร่กระจายแบบกลุ่มวิธีการนี้อาจเร็วกว่าเพราะช่วยลดการสื่อสารระหว่างโหนดที่เกี่ยวข้อง จากนั้นจึงสามารถใช้กลยุทธ์การเพิ่มประสิทธิภาพที่พิจารณาถึงลักษณะของการเปลี่ยนแปลงที่เกิดขึ้น และทำการเปลี่ยนแปลงตามนั้น (เช่น การเปลี่ยนแปลงสองรายการในกลุ่มอาจหักล้างกันเอง ดังนั้นจึงสามารถละเลยได้) อีกแนวทางหนึ่งที่ใช้ได้คือการแพร่กระจายการแจ้งเตือนความไม่ถูกต้องแนวทางนี้ทำให้โหนดที่มีข้อมูลป้อนเข้าไม่ถูกต้องดึงข้อมูลอัปเดต ส่งผลให้มีการอัปเดตเอาต์พุตของตนเองด้วย

มีสองวิธีหลักที่ใช้ในการสร้างกราฟความสัมพันธ์ :

  1. กราฟแสดงความสัมพันธ์แบบพึ่งพาจะถูกรักษาไว้โดยปริยายภายในลูปเหตุการณ์การลงทะเบียนฟังก์ชันเรียกกลับแบบชัดเจนจะส่งผลให้เกิดความสัมพันธ์แบบพึ่งพาโดยปริยาย ดังนั้นการกลับด้านการควบคุมซึ่งเกิดขึ้นผ่านฟังก์ชันเรียกกลับ จึงยังคงอยู่ อย่างไรก็ตาม การทำให้ฟังก์ชันเรียกกลับเป็นแบบฟังก์ชัน (เช่น ส่งคืนค่าสถานะแทนที่จะเป็นค่าหน่วย) จำเป็นต้องให้ฟังก์ชันเรียกกลับเหล่านั้นเป็นแบบประกอบกันได้
  2. กราฟแสดงความสัมพันธ์ระหว่างโปรแกรมนั้นสร้างขึ้นโดยโปรแกรมเมอร์ ซึ่งช่วยให้สามารถจัดการกับปัญหาการกลับด้านการควบคุม ของฟังก์ชันเรียกกลับ ได้สองวิธี คือ การระบุกราฟอย่างชัดเจน (โดยทั่วไปใช้ภาษาเฉพาะโดเมน (DSL) ซึ่งอาจฝังอยู่ภายใน) หรือการกำหนดกราฟโดยปริยายด้วยการแสดงออกและการสร้างโดยใช้ภาษาต้นแบบ ที่มีประสิทธิภาพ

ความท้าทายในการนำไปใช้ในการเขียนโปรแกรมเชิงปฏิกิริยา

ข้อผิดพลาด

เมื่อทำการเผยแพร่การเปลี่ยนแปลง เราสามารถเลือกลำดับการเผยแพร่ได้เพื่อให้ค่าของนิพจน์ไม่ได้เป็นผลลัพธ์ตามธรรมชาติของโปรแกรมต้นฉบับ เราสามารถอธิบายเรื่องนี้ได้ง่ายๆ ด้วยตัวอย่าง สมมติว่าsecondsเป็นค่าแบบตอบสนองที่เปลี่ยนแปลงทุกวินาทีเพื่อแสดงเวลาปัจจุบัน (ในหน่วยวินาที) พิจารณานิพจน์นี้:

t = วินาที + 1 g = (t > วินาที) 

เนื่องจากtค่า ควรมากกว่า เสมอ ดังนั้นsecondsนิพจน์นี้จึงควรมีค่าเป็นจริงเสมอ แต่น่าเสียดายที่ผลลัพธ์อาจขึ้นอยู่กับลำดับการประเมิน เมื่อsecondsค่า เปลี่ยนแปลง นิพจน์สองตัวจะต้องได้รับการอัปเดต ได้แก่seconds + 1และเงื่อนไข หากนิพจน์แรกได้รับการประเมินก่อนนิพจน์ที่สอง เงื่อนไขนี้ก็จะเป็นจริง อย่างไรก็ตาม หากเงื่อนไขได้รับการอัปเดตก่อน โดยใช้ค่าเก่าของtและค่าใหม่ของsecondsนิพจน์นั้นจะมีค่าเป็นเท็จ นี่เรียกว่าข้อผิดพลาด (glitch )

ภาษาโปรแกรมเชิงตอบสนองบางภาษานั้นปราศจากข้อผิดพลาดและพิสูจน์คุณสมบัตินี้ได้ โดยปกติแล้วจะทำได้โดยการเรียงลำดับนิพจน์ตามลำดับโทโพโลยีและอัปเดตค่าตามลำดับโทโพโลยี อย่างไรก็ตาม วิธีนี้อาจส่งผลกระทบต่อประสิทธิภาพ เช่น การส่งค่าล่าช้า (เนื่องจากลำดับการแพร่กระจาย) ดังนั้น ในบางกรณี ภาษาโปรแกรมเชิงตอบสนองจึงอนุญาตให้เกิดข้อผิดพลาดได้ และนักพัฒนาต้องตระหนักถึงความเป็นไปได้ที่ค่าอาจไม่ตรงกับซอร์สโค้ดของโปรแกรมชั่วคราว และนิพจน์บางอย่างอาจประเมินค่าหลายครั้ง (ตัวอย่างเช่นt > secondsอาจประเมินค่าสองครั้ง: ครั้งแรกเมื่อค่าใหม่ของsecondsมาถึง และอีกครั้งเมื่อtมีการอัปเดต)

การพึ่งพาแบบวัฏจักร

การเรียงลำดับความสัมพันธ์เชิงโทโพโลยีขึ้นอยู่กับว่ากราฟความสัมพันธ์นั้นเป็นกราฟแบบมีทิศทางและไม่มีวงจร (DAG) หรือไม่ ในทางปฏิบัติ โปรแกรมอาจกำหนดกราฟความสัมพันธ์ที่มีวงจรได้ โดยปกติแล้ว ภาษาโปรแกรมเชิงปฏิกิริยาจะคาดหวังว่าวงจรดังกล่าวจะถูก "ทำลาย" โดยการวางองค์ประกอบบางอย่างไว้ตาม "ขอบย้อนกลับ" เพื่อให้การอัปเดตเชิงปฏิกิริยาสิ้นสุดลง โดยทั่วไป ภาษาต่างๆ จะมีตัวดำเนินการเช่น `true` delayซึ่งกลไกการอัปเดตใช้เพื่อจุดประสงค์นี้ เนื่องจาก `false` delayหมายความว่าสิ่งที่ตามมาจะต้องได้รับการประเมินใน "ขั้นตอนเวลาถัดไป" (ทำให้การประเมินปัจจุบันสิ้นสุดลงได้)

การโต้ตอบกับสถานะที่เปลี่ยนแปลงได้

โดยทั่วไปแล้ว ภาษาโปรแกรมเชิงปฏิกิริยาจะถือว่านิพจน์ของมันเป็นฟังก์ชันล้วนๆซึ่งทำให้กลไกการอัปเดตสามารถเลือกลำดับที่แตกต่างกันในการดำเนินการอัปเดตได้ และปล่อยให้ลำดับที่เฉพาะเจาะจงไม่ระบุไว้ (จึงทำให้สามารถเพิ่มประสิทธิภาพได้) อย่างไรก็ตาม เมื่อภาษาโปรแกรมเชิงปฏิกิริยาถูกฝังอยู่ในภาษาโปรแกรมที่มีสถานะ โปรแกรมเมอร์อาจสามารถดำเนินการเปลี่ยนแปลงข้อมูลได้ วิธีการทำให้การทำงานร่วมกันนี้ราบรื่นยังคงเป็นปัญหาที่ยังไม่มีคำตอบ

ในบางกรณี อาจสามารถหาทางออกบางส่วนที่มีหลักการได้ ทางออกสองประการดังกล่าว ได้แก่:

  • ภาษาอาจมีแนวคิดเกี่ยวกับ "เซลล์ที่เปลี่ยนแปลงได้" เซลล์ที่เปลี่ยนแปลงได้คือเซลล์ที่ระบบอัปเดตแบบตอบสนองรับรู้ได้ ดังนั้นการเปลี่ยนแปลงที่เกิดขึ้นกับเซลล์จะแพร่กระจายไปยังส่วนที่เหลือของโปรแกรมแบบตอบสนอง ซึ่งทำให้ส่วนที่ไม่ตอบสนองของโปรแกรมสามารถทำการเปลี่ยนแปลงแบบดั้งเดิมได้ ในขณะที่โค้ดแบบตอบสนองสามารถรับรู้และตอบสนองต่อการอัปเดตนี้ได้ จึงรักษาความสอดคล้องของความสัมพันธ์ระหว่างค่าต่างๆ ในโปรแกรม ตัวอย่างของภาษาแบบตอบสนองที่ให้เซลล์ดังกล่าวคือ FrTime [ 4 ]
  • ไลบรารีเชิงวัตถุที่มีการห่อหุ้มอย่างเหมาะสมจะนำเสนอแนวคิดเรื่องสถานะที่ถูกห่อหุ้มไว้ ในทางทฤษฎีแล้ว ไลบรารีดังกล่าวจึงสามารถโต้ตอบกับส่วนตอบสนองของภาษาได้อย่างราบรื่น ตัวอย่างเช่น สามารถติดตั้งฟังก์ชันเรียกกลับใน getter ของไลบรารีเชิงวัตถุเพื่อแจ้งให้เอ็นจิ้นการอัปเดตแบบตอบสนองทราบเกี่ยวกับการเปลี่ยนแปลงสถานะ และสามารถผลักดันการเปลี่ยนแปลงในส่วนประกอบแบบตอบสนองไปยังไลบรารีเชิงวัตถุผ่าน getter ได้ FrTime ใช้กลยุทธ์ดังกล่าว[ 5 ]

การอัปเดตกราฟความสัมพันธ์แบบไดนามิก

ในบางภาษาโปรแกรมเชิงปฏิกิริยา กราฟแสดงความสัมพันธ์จะเป็นแบบคงที่ กล่าวคือ กราฟจะคงที่ตลอดการทำงานของโปรแกรม ในขณะที่ภาษาอื่นๆ กราฟอาจเป็นแบบไดนามิกกล่าวคือ สามารถเปลี่ยนแปลงได้ขณะที่โปรแกรมทำงาน เพื่อความเข้าใจง่าย ลองพิจารณาตัวอย่างต่อไปนี้ (โดยที่secondsเป็นค่าเชิงปฏิกิริยา):

t = ถ้า ((วินาที mod 2) == 0): วินาที + 1 อื่น: วินาที - 1 จบ t + 1 

ทุกวินาที ค่าของนิพจน์นี้จะเปลี่ยนไปเป็นนิพจน์ตอบสนองอื่น ซึ่งt + 1จะขึ้นอยู่กับนิพจน์อื่นต่อไป ดังนั้น กราฟความสัมพันธ์จึงอัปเดตทุกวินาที

การอนุญาตให้มีการอัปเดตความสัมพันธ์แบบไดนามิกช่วยเพิ่มพลังในการแสดงออกอย่างมาก (ตัวอย่างเช่น ความสัมพันธ์แบบไดนามิกมักเกิดขึ้นใน โปรแกรม ส่วนติดต่อผู้ใช้แบบกราฟิก (GUI)) อย่างไรก็ตาม กลไกการอัปเดตแบบตอบสนองต้องตัดสินใจว่าจะสร้างนิพจน์ขึ้นใหม่ทุกครั้ง หรือจะคงโหนดของนิพจน์ไว้แต่ไม่ทำงาน ในกรณีหลัง ต้องแน่ใจว่าโหนดเหล่านั้นจะไม่เข้าร่วมในการคำนวณเมื่อไม่ควรทำงาน

แนวคิด

ระดับความชัดเจน

ภาษาโปรแกรมเชิงตอบสนอง (Reactive Programming) มีตั้งแต่แบบที่ชัดเจนมาก โดยกำหนดการไหลของข้อมูลโดยใช้ลูกศร ไปจนถึงแบบไม่ชัดเจน ซึ่งการไหลของข้อมูลได้มาจากโครงสร้างภาษาที่คล้ายกับภาษาโปรแกรมเชิงคำสั่งหรือเชิงฟังก์ชัน ตัวอย่างเช่น ในภาษาโปรแกรมเชิงตอบสนอง แบบยกขึ้น โดยปริยาย (Implicitly Lifted Functional Reactive Programming: FRP) การเรียกฟังก์ชันอาจทำให้เกิดการสร้างโหนดในกราฟการไหลของข้อมูลโดยปริยาย ไลบรารีการเขียนโปรแกรมเชิงตอบสนองสำหรับภาษาแบบไดนามิก (เช่น ไลบรารี "Cells" ของ Lisp และ "Trellis" ของ Python) สามารถสร้างกราฟการพึ่งพาจากการวิเคราะห์ค่าที่อ่านได้ระหว่างการทำงานของฟังก์ชัน ทำให้การกำหนดการไหลของข้อมูลเป็นได้ทั้งแบบไม่ชัดเจนและแบบไดนามิก

บางครั้ง คำว่าการเขียนโปรแกรมเชิงปฏิกิริยา (reactive programming)หมายถึงระดับสถาปัตยกรรมของวิศวกรรมซอฟต์แวร์ ซึ่งแต่ละโหนดในกราฟการไหลของข้อมูลเป็นโปรแกรมธรรมดาที่สื่อสารกัน

แบบคงที่หรือแบบไดนามิก

การเขียนโปรแกรมเชิงปฏิกิริยาสามารถเป็นแบบคงที่โดยสมบูรณ์ ซึ่งการไหลของข้อมูลถูกกำหนดไว้แบบคงที่ หรือเป็นแบบไดนามิก ซึ่งการไหลของข้อมูลสามารถเปลี่ยนแปลงได้ในระหว่างการทำงานของโปรแกรม

การใช้สวิตช์ข้อมูลในกราฟการไหลของข้อมูลอาจทำให้กราฟการไหลของข้อมูลแบบคงที่ดูเหมือนแบบไดนามิกได้ในระดับหนึ่ง และทำให้ความแตกต่างระหว่างสองแบบนี้ไม่ชัดเจนนัก อย่างไรก็ตาม การเขียนโปรแกรมแบบไดนามิกเชิงตอบสนองที่แท้จริงสามารถใช้การเขียนโปรแกรมเชิงคำสั่งเพื่อสร้างกราฟการไหลของข้อมูลขึ้นใหม่ได้

การเขียนโปรแกรมเชิงปฏิกิริยาระดับสูง

อาจกล่าวได้ว่าการเขียนโปรแกรมเชิงปฏิกิริยา (Reactive programming) มีลำดับสูงกว่าหากสนับสนุนแนวคิดที่ว่ากระแสข้อมูลสามารถนำมาใช้สร้างกระแสข้อมูลอื่นได้ กล่าวคือ ค่าที่ได้จากกระแสข้อมูลหนึ่งจะเป็นกราฟกระแสข้อมูลอีกกราฟหนึ่งที่ถูกประมวลผลโดยใช้แบบจำลองการประเมินค่าแบบเดียวกับกราฟแรก

การจำแนกความแตกต่างของการไหลของข้อมูล

ตามหลักการแล้ว การเปลี่ยนแปลงข้อมูลทั้งหมดควรถูกส่งต่อทันที แต่ในทางปฏิบัตินั้นไม่สามารถรับประกันได้ ดังนั้น อาจจำเป็นต้องกำหนดลำดับความสำคัญในการประเมินที่แตกต่างกันให้กับส่วนต่างๆ ของกราฟการไหลของข้อมูล ซึ่งเรียกว่า การเขียนโปรแกรมเชิงตอบสนองแบบแยกแยะ (Differentiated Reactive Programming )

ตัวอย่างเช่น ในโปรแกรมประมวลผลคำการตรวจสอบการสะกดคำผิดไม่จำเป็นต้องซิงโครไนซ์กับการเพิ่มหรือแทรกตัวอักษรอย่างสมบูรณ์ ในกรณีนี้ สามารถใช้การเขียนโปรแกรมเชิงตอบสนองแบบแยกส่วน (differentiated reactive programming) เพื่อกำหนดลำดับความสำคัญที่ต่ำกว่าให้กับโปรแกรมตรวจสอบการสะกดคำทำให้สามารถหน่วงเวลาการตรวจสอบได้ ในขณะที่การไหลของข้อมูลอื่นๆ ยังคงเกิดขึ้นทันที

อย่างไรก็ตาม การแบ่งแยกเช่นนี้ทำให้การออกแบบมีความซับซ้อนมากขึ้น ตัวอย่างเช่น การตัดสินใจว่าจะกำหนดพื้นที่การไหลของข้อมูลที่แตกต่างกันอย่างไร และจะจัดการกับการส่งผ่านเหตุการณ์ระหว่างพื้นที่การไหลของข้อมูลที่แตกต่างกันอย่างไร

แบบจำลองการประเมินผลของการเขียนโปรแกรมเชิงตอบสนอง

การประเมินโปรแกรมแบบรีแอคทีฟไม่จำเป็นต้องอิงตามวิธีการประเมินของภาษาโปรแกรมแบบใช้สแต็กเสมอไป แต่เมื่อข้อมูลบางส่วนเปลี่ยนแปลง การเปลี่ยนแปลงนั้นจะถูกส่งต่อไปยังข้อมูลทั้งหมดที่ได้มาจากข้อมูลที่เปลี่ยนแปลงนั้นบางส่วนหรือทั้งหมด การส่งต่อการเปลี่ยนแปลงนี้สามารถทำได้หลายวิธี ซึ่งวิธีที่ดูเป็นธรรมชาติที่สุดอาจจะเป็นการใช้กลไก invalidate/lazy-revalidate

การใช้สแต็กเพื่อส่งต่อการเปลี่ยนแปลงโดยไม่พิจารณาอย่างรอบคอบอาจเป็นปัญหาได้ เนื่องจากความซับซ้อนในการอัปเดตอาจเพิ่มขึ้นแบบทวีคูณหากโครงสร้างข้อมูลมีรูปร่างเฉพาะ รูปร่างหนึ่งที่สามารถอธิบายได้คือ "รูปร่างเพชรซ้ำ" ซึ่งมีโครงสร้างดังนี้: A n →B n →A n+1 , A n →C n →A n+1โดยที่ n=1,2... ปัญหานี้สามารถแก้ไขได้โดยการส่งต่อการทำให้ไม่ถูกต้องเฉพาะเมื่อข้อมูลบางส่วนยังไม่ถูกทำให้ไม่ถูกต้อง และตรวจสอบความถูกต้องของข้อมูลอีกครั้งในภายหลังเมื่อจำเป็นโดยใช้การประเมินแบบเลซี่ (lazy evaluation )

ปัญหาหนึ่งที่สำคัญของการเขียนโปรแกรมเชิงปฏิกิริยาคือ การคำนวณส่วนใหญ่ที่จะถูกประเมินและลืมไปในภาษาการเขียนโปรแกรมปกติ จำเป็นต้องแสดงในหน่วยความจำในรูปแบบของโครงสร้างข้อมูล ซึ่งอาจทำให้การเขียนโปรแกรมเชิงปฏิกิริยาสิ้นเปลืองหน่วยความจำอย่างมาก อย่างไรก็ตาม การวิจัยเกี่ยวกับสิ่งที่เรียกว่าการลดระดับอาจช่วยแก้ไขปัญหานี้ได้[ 6 ]

ในทางกลับกัน การเขียนโปรแกรมเชิงปฏิกิริยาเป็นรูปแบบหนึ่งของสิ่งที่อาจอธิบายได้ว่าเป็น "การประมวลผลแบบขนานอย่างชัดเจน" และดังนั้นจึงอาจเป็นประโยชน์สำหรับการใช้ประโยชน์จากพลังของฮาร์ดแวร์แบบขนาน

ความคล้ายคลึงกับรูปแบบการสังเกต

การเขียนโปรแกรมเชิงปฏิกิริยา (Reactive Programming) มีความคล้ายคลึงกันในหลักการกับรูปแบบผู้สังเกตการณ์ (Observer Pattern)ที่ใช้กันทั่วไปในการเขียนโปรแกรมเชิงวัตถุ (Object-Oriented Programming) อย่างไรก็ตาม การบูรณาการแนวคิดการไหลของข้อมูลเข้ากับภาษาการเขียนโปรแกรมจะทำให้การแสดงออกง่ายขึ้น และสามารถเพิ่มระดับความละเอียดของกราฟการไหลของข้อมูลได้ ตัวอย่างเช่น รูปแบบผู้สังเกตการณ์มักอธิบายการไหลของข้อมูลระหว่างวัตถุ/คลาสทั้งหมด ในขณะที่การเขียนโปรแกรมเชิงปฏิกิริยาแบบเชิงวัตถุสามารถกำหนดเป้าหมายไปที่สมาชิกของวัตถุ/คลาสได้

แนวทาง

คำสั่ง

เป็นไปได้ที่จะผสานการเขียนโปรแกรมเชิงปฏิกิริยากับการเขียนโปรแกรมเชิงคำสั่ง ทั่วไป ในรูปแบบดังกล่าว โปรแกรมเชิงคำสั่งจะทำงานกับโครงสร้างข้อมูลเชิงปฏิกิริยา[ 7 ]การตั้งค่าดังกล่าวคล้ายคลึงกับการเขียนโปรแกรมเชิงข้อจำกัด เชิงคำสั่ง อย่างไรก็ตาม ในขณะที่การเขียนโปรแกรมเชิงข้อจำกัดเชิงคำสั่งจัดการข้อจำกัดการไหลของข้อมูลแบบสองทิศทาง การเขียนโปรแกรมเชิงปฏิกิริยาเชิงคำสั่งจะจัดการข้อจำกัดการไหลของข้อมูลแบบทางเดียว การใช้งานอ้างอิงหนึ่งคือส่วนขยายรันไทม์ Quantum ที่เสนอสำหรับ JavaScript

เชิงวัตถุ

การเขียนโปรแกรมเชิงวัตถุแบบตอบสนอง (Object-oriented reactive programming หรือ OORP) คือการผสมผสานระหว่างการเขียนโปรแกรมเชิงวัตถุและการเขียนโปรแกรมแบบตอบสนอง วิธีที่ลงตัวที่สุดในการผสมผสานนี้คือ แทนที่จะใช้เมธอดและฟิลด์ วัตถุจะมีปฏิกิริยาตอบสนองที่ประเมินค่าใหม่โดยอัตโนมัติเมื่อปฏิกิริยาตอบสนองอื่นๆ ที่มันขึ้นอยู่ด้วยมีการเปลี่ยนแปลง

หากภาษา OORP ยังคงรักษาวิธีการเชิงคำสั่งเอาไว้ ภาษาดังกล่าวก็จะจัดอยู่ในหมวดหมู่ของการเขียนโปรแกรมเชิงปฏิกิริยาแบบเชิงคำสั่งด้วยเช่นกัน

การทำงาน

การเขียนโปรแกรมเชิงปฏิกิริยาแบบฟังก์ชัน (Functional Reactive Programming หรือ FRP) เป็นรูปแบบการเขียนโปรแกรมสำหรับการเขียนโปรแกรมเชิงปฏิกิริยาบนพื้นฐานของการเขียนโปรแกรมเชิงฟังก์ชัน

นักแสดง

แบบจำลองนักแสดง (นักแสดง) ได้รับการเสนอเพื่อออกแบบระบบปฏิกิริยา โดยมักจะรวมกับการเขียนโปรแกรมปฏิกิริยาเชิงฟังก์ชัน (FRP) และกระแสปฏิกิริยาเพื่อพัฒนาระบบปฏิกิริยาแบบกระจาย[ 8 ] [ 9 ] [ 10 ] [ 11 ]

ตามกฎเกณฑ์

ภาษาโปรแกรมประเภทใหม่ใช้ข้อจำกัด (กฎ) เป็นแนวคิดหลักในการเขียนโปรแกรม ประกอบด้วยปฏิกิริยาต่อเหตุการณ์ ซึ่งทำให้ข้อจำกัดทั้งหมดเป็นไปตามเงื่อนไข ไม่เพียงแต่จะอำนวยความสะดวกในการตอบสนองตามเหตุการณ์เท่านั้น แต่ยังทำให้โปรแกรมแบบตอบสนองเป็นเครื่องมือสำคัญต่อความถูกต้องของซอฟต์แวร์ ตัวอย่างของภาษาโปรแกรมแบบตอบสนองตามกฎคือ Ampersand ซึ่งมีพื้นฐานมาจากพีชคณิตเชิงสัมพันธ์[ 12 ]

การนำไปใช้

  • Elmคือองค์ประกอบที่ตอบสนองต่อสิ่งรอบข้างของส่วนติดต่อผู้ใช้บนเว็บ
  • ObservableComputations คือ การใช้งาน . NETแบบข้ามแพลตฟอร์ม
  • Quantum JSคือส่วนขยายรันไทม์ของ JavaScript ที่นำการเขียนโปรแกรมเชิงปฏิกิริยาแบบเชิงคำสั่งมาสู่ภาษา สร้างหมวดหมู่ใหม่ทั้งหมดในสเปกตรัมของการตอบสนอง
  • Reactive Streamsคือมาตรฐานของ JVM สำหรับการประมวลผลสตรีมแบบอะซิงโครนัสพร้อมกลไกควบคุมแรงดันย้อนกลับแบบไม่ปิดกั้น
  • ReactiveXคือ API สำหรับการใช้งานการเขียนโปรแกรมเชิงปฏิกิริยา (reactive programming) ด้วยสตรีม ออบเซอร์เวเบิล และโอเปอเรเตอร์ โดยมีเวอร์ชันสำหรับหลายภาษา ได้แก่ RxJs, RxJava, Rx.NET, RxPy และ RxSwift
  • Rimmel.jsเป็นไลบรารี JavaScript สำหรับ UI ที่เน้นการประมวลผลแบบสตรีม ออกแบบมาเพื่อใช้งานร่วมกับ RxJS และ Observables
  • Shinyเป็นเฟรมเวิร์กเว็บแบบโอเพนซอร์สจากPosit PBCที่ช่วยให้สามารถพัฒนาเว็บแอปพลิเคชันแบบตอบสนองและโต้ตอบได้โดยใช้ R หรือ Python พร้อมตัวเลือกการใช้งานที่หลากหลาย ตั้งแต่บริการบนคลาวด์ไปจนถึงการใช้งานในคอนเทนเนอร์ภายในองค์กร
  • Solid.jsนำเสนอการตอบสนองแบบเรียลไทม์ให้กับJavaScriptโดยไม่เปลี่ยนแปลง ความหมาย ทางไวยากรณ์ของ JavaScriptพร้อมทั้งยังรองรับการสร้างเทมเพลตJSX แบบเรียลไทม์อีกด้วย
  • Svelteนำเสนอความสามารถในการตอบสนองแบบเรียลไทม์ในรูปแบบของไวยากรณ์JavaScriptที่มีลักษณะคล้ายJavaScriptแต่โดยธรรมชาติแล้วสามารถตอบสนองได้ทันทีในจุดที่ JavaScript ทั่วไปไม่สามารถทำได้

ดูเพิ่มเติม

ดึงข้อมูลมาจาก " https://en.wikipedia.org/w/index.php?title=Reactive_programming&oldid=1358342499 "

สรุปเนื้อหา

ข้อมูลสำคัญจากบทความ

ข้อมูลสำคัญเกี่ยวกับ การเขียนโปรแกรมเชิงตอบสนอง

ในด้านการคำนวณการเขียนโปรแกรมเชิงปฏิกิริยา (Reactive Programming)เป็นกระบวนทัศน์การเขียนโปรแกรมเชิงประกาศ ที่เกี่ยวข้องกับกระแสข้อมูลและการแพร่กระจายของการเปลี่ยนแปลง...

แนวทางการสร้างภาษาโปรแกรมเชิงตอบสนอง

มีแนวทางที่เป็นที่นิยมหลายวิธีในการสร้างภาษาโปรแกรมเชิงตอบสนอง (reactive programming languages) แนวทางหนึ่งคือการกำหนด ภาษา เฉพาะ ที่ใช้กับ ข้อจำกัดต่างๆ ในโดเมน ข้อจำกัดเหล่านี้มักเกี่ยวข้องกับระบบเรียลไทม์ การประมวลผลแบบฝังตัว หรือคำอธิบายฮาร์ดแวร์...

แบบจำลองการเขียนโปรแกรมและความหมาย

การเขียนโปรแกรมเชิงตอบสนอง (Reactive Programming) มีรูปแบบและ ความหมายที่ หลากหลายซึ่งสามารถแบ่งออกอย่างคร่าวๆ ได้เป็นสามมิติ:

สาระสำคัญของการนำไปปฏิบัติ

ระบบรันไทม์ของภาษาโปรแกรมเชิงปฏิกิริยาจะถูกแสดงด้วยกราฟที่ระบุความสัมพันธ์ระหว่างค่าเชิงปฏิกิริยาที่เกี่ยวข้อง ในกราฟดังกล่าว โหนด แสดงถึงการกระทำของการคำนวณ และ ขอบ แสดง ถึงความสัมพันธ์ของการพึ่งพา...