ประสิทธิภาพของการเขียนโปรแกรมการทำงานอย่างหมดจด


397

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

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


6
เช่นเดียวกับเมื่อการเขียนโปรแกรมจำเป็นอย่างไม่ว่าจะเป็นอะไรก็ตาม
R. Martinho Fernandes

3
@jldupont: เพื่อส่งคืนผลลัพธ์ของการคำนวณแน่นอน มีโปรแกรมฟรีผลข้างเคียงมากมาย พวกเขาไม่สามารถทำอะไรได้มากไปกว่าการคำนวณอินพุตของพวกเขา แต่นั่นก็ยังมีประโยชน์
jalf

24
ฉันสามารถทำให้มันแย่ได้ตามที่คุณต้องการโดยการเขียนโค้ดฟังก์ชั่นของฉันไม่ดี! * ยิ้ม * ฉันคิดว่าสิ่งที่คุณถามคือ "จะมีปัญหาใดบ้างที่อัลกอริทึมแบบไม่ทำลายที่รู้จักกันดีที่สุดนั้นเลวร้ายกว่าอัลกอริธึมการทำลายที่รู้จักกันดีที่สุดและถ้าเป็นเช่นนั้นเท่าใด?" ... ?
itowlson

2
คุณช่วยยกตัวอย่างประเภทของการชะลอตัวที่คุณสนใจคำถามของคุณค่อนข้างคลุมเครือ
Peter Recore

5
ผู้ใช้ลบคำตอบของเขา แต่เขาอ้างว่าปัญหาการทำงานของ 8-ควีนส์ทำงานได้ในหนึ่งนาทีสำหรับ n = 13 เขายอมรับว่ามันไม่ใช่ "เขียนได้ดีมาก" ดังนั้นฉันจึงตัดสินใจเขียนเวอร์ชันของตัวเอง 8 ราชินีใน F #: pastebin.com/ffa8d4c4 โปรแกรมฟังก์ชั่นของฉันล้วนคำนวณ n = 20 ได้ในเวลาไม่กี่วินาที
Juliet

คำตอบ:


531

ตามPippenger [1996]เมื่อเปรียบเทียบระบบ LISP ที่สามารถใช้งานได้อย่างหมดจด (และมีความหมายการประเมินที่เข้มงวดไม่ขี้เกียจ) กับสิ่งที่สามารถกลายพันธุ์ข้อมูลอัลกอริทึมที่เขียนสำหรับ Lisp ที่ไม่บริสุทธิ์ที่ทำงานใน O ( n ) สู่อัลกอริทึมใน Lisp บริสุทธิ์ที่ทำงานในเวลา O ( n log n ) (ขึ้นอยู่กับการทำงานของBen-Amram และ Galil [1992]เกี่ยวกับการจำลองหน่วยความจำเข้าถึงโดยใช้ตัวชี้เท่านั้น) Pippenger สร้างว่ามีอัลกอริธึมที่ดีที่สุดที่คุณสามารถทำได้ มีปัญหาที่เป็น O ( n ) ในระบบที่ไม่บริสุทธิ์ซึ่งเป็นΩ ( n log n ) ในระบบบริสุทธิ์

มีคำเตือนเล็กน้อยที่จะทำเกี่ยวกับกระดาษนี้ สิ่งที่สำคัญที่สุดคือมันไม่ได้ใช้ภาษาที่ขี้เกียจเช่น Haskell เบิร์ดโจนส์และเดอมัวร์ [1997]แสดงให้เห็นว่าปัญหาที่สร้างขึ้นโดย Pippenger สามารถแก้ไขได้ในภาษาหน้าที่ขี้เกียจใน O ( n ) เวลา แต่พวกเขาไม่ได้สร้าง (และเท่าที่ฉันรู้ไม่มีใครมี) หรือ ไม่ใช่ภาษาที่ใช้งานได้อย่างขี้เกียจสามารถแก้ไขปัญหาทั้งหมดได้ในเวลาทำงานแบบ asymptotic เช่นเดียวกับภาษาที่มีการกลายพันธุ์

ปัญหาที่สร้างโดย Pippenger ต้องการΩ ( n log n ) ถูกสร้างขึ้นเป็นพิเศษเพื่อให้ได้ผลลัพธ์นี้และไม่จำเป็นต้องเป็นตัวแทนของปัญหาที่เกิดขึ้นจริงในทางปฏิบัติ มีข้อ จำกัด บางประการเกี่ยวกับปัญหาที่คาดไม่ถึง แต่จำเป็นสำหรับการพิสูจน์การทำงาน โดยเฉพาะอย่างยิ่งปัญหาต้องการให้มีการคำนวณผลลัพธ์แบบออนไลน์โดยไม่สามารถเข้าถึงอินพุตในอนาคตและอินพุตประกอบด้วยลำดับของอะตอมจากชุดอะตอมที่เป็นไปได้ที่ไม่ จำกัด มากมายแทนที่จะเป็นชุดขนาดคงที่ และกระดาษจะสร้างผลลัพธ์ (ขอบเขตล่าง) สำหรับอัลกอริธึมที่ไม่บริสุทธิ์ของเวลาการทำงานแบบเชิงเส้นเท่านั้น สำหรับปัญหาที่ต้องใช้เวลามากขึ้นเป็นไปได้ที่ O พิเศษ (log n) ปัจจัยที่พบในปัญหาเชิงเส้นอาจจะ "หมกมุ่น" ในกระบวนการของการดำเนินการพิเศษที่จำเป็นสำหรับอัลกอริทึมที่มีเวลาทำงานมากขึ้น ชี้แจงคำถามเหล่านี้และเปิดให้มีการสำรวจโดยสังเขปเบนอัมราม [1996]

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

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

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

อ้างอิง


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

6
itowlson: ฉันต้องยอมรับว่าฉันอ่าน Pippenger ไม่เพียงพอที่จะตอบคำถามของคุณ; มันถูกตีพิมพ์ในวารสารที่ได้รับการตรวจสอบโดยเพื่อนโดย Okasaki และฉันอ่านให้มากพอที่จะตัดสินว่าข้อเรียกร้องของเขาเกี่ยวข้องกับคำถามนี้ แต่ไม่เพียงพอที่จะเข้าใจหลักฐาน Takeaway ทันทีที่ฉันได้รับผลที่ตามมาในโลกแห่งความจริงก็คือมันเป็นเรื่องเล็กน้อยที่จะแปลง O ( n ) ขั้นตอนวิธีที่ไม่บริสุทธิ์ให้เป็น O ( n log n ) อันบริสุทธิ์โดยการจำลองหน่วยความจำที่สามารถแก้ไขได้โดยใช้ต้นไม้ไบนารีที่สมดุล มีปัญหาที่ไม่สามารถทำได้ดีกว่านั้น ฉันไม่รู้ว่าพวกมันเป็นทฤษฎีล้วนๆหรือไม่
Brian Campbell

3
ผลลัพธ์ Pippenger สร้างสมมติฐานที่สำคัญสองข้อที่ จำกัด ขอบเขต: พิจารณา "การคำนวณออนไลน์" หรือ "ปฏิกิริยา" (ไม่ใช่รูปแบบปกติของการคำนวณการแมปอินพุต จำกัด ไปยังเอาต์พุตเดียว) และการคำนวณ "สัญลักษณ์" ที่อินพุตเป็นลำดับของ อะตอมซึ่งสามารถทดสอบได้เพื่อความเท่าเทียมเท่านั้น (เช่นการแปลความหมายของอินพุตนั้นดั้งเดิมมาก)
Chris Conway

2
คำตอบที่ดีมาก ฉันต้องการเพิ่มว่าสำหรับภาษาที่ใช้งานได้จริงไม่มีรูปแบบการตกลงกันอย่างแพร่หลายสำหรับความซับซ้อนในการคำนวณในขณะที่ในโลกที่ไม่บริสุทธิ์เครื่อง RAM ราคาต่อหน่วยนั้นค่อนข้างมาตรฐาน (ดังนั้นนี่เป็นการเปรียบเทียบสิ่งที่ยากกว่า) โปรดทราบว่าขอบเขตบนของความแตกต่าง Lg (N) บริสุทธิ์ / ไม่บริสุทธิ์สามารถอธิบายได้อย่างง่ายดายโดยการดูการใช้งานของอาร์เรย์ในภาษาบริสุทธิ์ (มีค่าใช้จ่าย lg (n) ต่อการดำเนินการ (และคุณได้รับประวัติ)) .
user51568

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

44

มีหลายอัลกอริธึมและโครงสร้างข้อมูลที่ไม่มีประสิทธิภาพอย่างแท้จริงในการแก้ปัญหาการทำงานแบบ asymptotically asymptotically (ti หนึ่ง implementable ในแลมบ์ดาบริสุทธิ์แคลคูลัส) เป็นที่รู้จักแม้ความเกียจคร้าน

  • สหภาพดังกล่าวค้นหา
  • ตารางแฮช
  • อาร์เรย์
  • อัลกอริทึมกราฟบางอย่าง
  • ...

อย่างไรก็ตามเราสันนิษฐานว่าในการเข้าถึงหน่วยความจำภาษา "จำเป็น" คือ O (1) ในทางทฤษฎีที่ไม่สามารถให้ asymptotically (เช่นขนาดปัญหาที่ไม่ จำกัด ) และการเข้าถึงหน่วยความจำภายในชุดข้อมูลขนาดใหญ่มักจะเป็น O (log n) ซึ่งสามารถเลียนแบบในภาษาที่ใช้งานได้

นอกจากนี้เราต้องจำไว้ว่าจริงๆแล้วภาษาที่ใช้งานได้จริงทั้งหมดจะให้ข้อมูลที่ไม่แน่นอนและ Haskell ก็ให้มันโดยไม่เสียสละความบริสุทธิ์ (ST monad)


3
หากชุดข้อมูลพอดีกับหน่วยความจำกายภาพการเข้าถึงคือ O (1) ซึ่งเป็นไปได้ที่จะหาขอบเขตบนแน่นอนในเวลาที่จะอ่านรายการใด ๆ หากชุดข้อมูลไม่ได้แสดงว่าคุณกำลังพูดถึง I / O และจะเป็นปัจจัยที่สำคัญในตอนนี้อย่างไรก็ตามโปรแกรมจะถูกเขียน
Donal Fellows

แน่นอนฉันกำลังพูดถึง O (log n) การทำงานของการเข้าถึงหน่วยความจำภายนอก อย่างไรก็ตามในกรณีใด ๆ ที่ฉันกำลังพูดถึง bs: หน่วยความจำภายนอกยังสามารถ O (1) - ทนต่อ ...
jkff

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

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

36

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

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

แก้ไข:

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

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

หากฟังก์ชั่นที่เข้มงวดมีความซับซ้อน O (f (n)) ในภาษาที่เข้มงวดก็จะมีความซับซ้อน O (f (n)) ในภาษาที่ขี้เกียจเช่นกัน กังวลทำไม? :)


4

ด้วยขอบเขตบนคงที่ในการใช้งานหน่วยความจำไม่ควรมีความแตกต่าง

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


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

@Brian Campbell: นั่นเป็นเรื่องจริง ฉันแค่แนะนำว่าถ้าคุณต้องการคุณสามารถเพิกเฉยความแตกต่างของปัจจัยคงที่ในหลาย ๆ กรณีในทางปฏิบัติ หนึ่งยังคงต้องคำนึงถึงความแตกต่างเมื่อการประนีประนอมระหว่างหน่วยความจำและเวลาเพื่อให้แน่ใจว่าการใช้ m คูณหน่วยความจำมากขึ้นจะลดการทำงานของคุณลงอย่างน้อยหนึ่งส่วนของ log (m)
Brian

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