ความแตกต่างระหว่างการเขียนโปรแกรมแบบขนานและแบบพร้อมกัน?


44

เมื่อดูที่การเขียนโปรแกรมพร้อมกันคำสองคำที่ใช้กันทั่วไปคือพร้อมกันและขนาน

และบางภาษาโปรแกรมเฉพาะเรียกร้องการสนับสนุนสำหรับการเขียนโปรแกรมแบบขนานเช่นJava

สิ่งนี้หมายความว่าการเขียนโปรแกรมแบบขนานและพร้อมกันนั้นแตกต่างกันจริงหรือ


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

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

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


1
Robert Harper กล่าวถึงปัญหาในสองโพสต์บล็อก"Parallelism ไม่ใช่การทำงานพร้อมกัน"และ"Parallelism and Concurrency, Revisited"ซึ่งคุณอาจต้องการตรวจสอบ
บาซิล

คำตอบ:


26

แยกความแตกต่างขนาน (ใช้หน่วยคำนวณพิเศษเพื่อทำงานต่อหน่วยเวลามากขึ้น) จากการทำงานพร้อมกัน (การจัดการการเข้าถึงทรัพยากรที่ใช้ร่วมกัน) สอนขนานแรกเพราะง่ายกว่าและช่วยสร้างความคิดที่ไม่ต่อเนื่อง

จาก "A Sophomoric ∗ บทนำสู่การแชร์หน่วยความจำและความพร้อมใช้งานร่วมกัน" โดย Dan Grossman (รุ่น 16 พฤศจิกายน 2013)


21

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

การอ้างอิงจากที่นั่น:

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

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

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

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

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

แนวคิดของ "เธรดการควบคุม" ไม่สมเหตุสมผลในโปรแกรมการทำงานอย่างหมดจดเนื่องจากไม่มีผลที่จะสังเกตและลำดับการประเมินผลไม่เกี่ยวข้อง ดังนั้นการทำงานพร้อมกันเป็นเทคนิคการสร้างรหัสที่มีประสิทธิผล ใน Haskell นั่นหมายถึงรหัสใน IO monad

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

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

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


20

การเห็นพ้องและขนานในปัญหาที่พวกเขาแก้ไขและก่อให้เกิด แต่พวกเขาไม่ได้เป็นอิสระ

เห็นพ้องด้วย

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

สิ่งนี้มีประโยชน์ในบางเรื่อง:

  • การเขียนโปรแกรมที่ชัดเจนของงานอิสระในโปรแกรมเดียว
  • อนุญาตให้จัดการกับ IO ขณะคำนวณ (เช่นใน GUI)
  • อนุญาตให้เรียกใช้งานมากกว่าหนึ่งโปรแกรมในเวลาเดียวกัน (การทำงานพร้อมกันในระดับระบบปฏิบัติการ)

ความท้าทายหลัก ๆ ได้แก่ :

  • รักษาความสอดคล้องของข้อมูล
  • หลีกเลี่ยงการติดตายและlivelocks
  • กำหนดความหมายที่แม่นยำของกระบวนการที่เกิดขึ้นพร้อมกัน
  • กำหนดคุณสมบัติคงที่ที่ถูกต้อง

ความเท่าเทียม

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

  • ปรับปรุงทรูพุตของระบบโดยการรันโปรแกรมแบบขนาน (เช่นในระบบมัลติคอร์)
  • ปรับปรุงรันไทม์ของแต่ละโปรแกรมโดยใช้หลาย CPU ในครั้งเดียว
  • ใช้ประโยชน์ IO ในหลาย ๆ เครื่อง (เช่นฐานข้อมูลแบบกระจาย)

ความท้าทายที่สำคัญ ได้แก่ :

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

ดูคำถามนี้เพื่อแยกความแตกต่างระหว่างการคำนวณแบบขนานและแบบกระจาย


4

คำตอบที่เงียบสงบเล็กน้อยอาจจะ ...

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

  • ขนานเป็นทรัพย์สินของวิธีการที่โปรแกรมรัน หากโปรแกรมดำเนินการกับหน่วยการคำนวณมากกว่าหนึ่งหน่วยพร้อมกันแสดงว่ามีการดำเนินการแบบขนาน


1

มีคำตอบมากมายในเรื่องนี้ แต่มันอาจทำให้สับสน ฉันชอบคิดแบบนี้และอาจช่วยได้:

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

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

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


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

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

สำหรับการอ่านเพิ่มเติมฉันชอบภาพประกอบในคำตอบที่ดีที่สุดสำหรับคำถามนี้ที่นี่: https://www.quora.com/What-are-the-differences-between-parallel-concurrent-and-asynchronous-programming

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.