Parallel“ any” หรือ“ all” ใน Haskell


9

รูปแบบที่ฉันเจอหลายครั้งตอนนี้เป็นสิ่งที่รายการค่าต้องตรวจสอบโดยการทำแผนที่การทดสอบบางอย่างและดูว่าองค์ประกอบใด ๆ หรือทั้งหมดผ่าน การแก้ปัญหาโดยทั่วไปเป็นเพียงการใช้งานที่สะดวก built-ins และallany

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

มันเป็นรูปแบบที่ค่อนข้างธรรมดาในวิชาคณิตศาสตร์ (เช่น Miller-Rabin Primality) ดังนั้นฉันรู้สึกว่ามีบางคนอาจคิดหาวิธีแก้ปัญหานี้อยู่แล้ว แต่ด้วยเหตุผลที่ชัดเจนในการค้นหา google สำหรับ "ขนานหรือ / และ / ใด ๆ / ทั้งหมดในรายการ Haskell "ไม่แสดงผลลัพธ์ที่เกี่ยวข้องหลายรายการ


1
คุณอาจพบขนานและการเขียนโปรแกรมพร้อมกันใน Haskellมีประโยชน์โดยเฉพาะอย่างยิ่งบทที่2 , 3และ4
bradrn

2
เป็นไปได้ด้วยunambห้องสมุด
luqui

1
@luqui ที่น่าสนใจ; ฉันจะยุ่งกับสิ่งนี้ ถ้าฉันเขียนดีขนานทั้งหมด / ใด ๆ กับสิ่งนี้ฉันจะโพสต์มันเป็นคำตอบ
Arcuritech

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

2
@chepner คุณกำลังพูดถึงอะไร? เราไม่ได้พูดถึงทุบตีที่นี่! เราสามารถทำพร้อมกันและขนานกับกระทู้ (ไม่ว่าจะเป็นpthreadsใน C หรือกระทู้สีเขียวใน Haskell) คุณ don เริ่มหลาย webservers เพื่อจัดการคำขอเว็บที่เกิดขึ้นพร้อมกันแทนคุณใช้หลายกระทู้ในกระบวนการเดียว! เช่นเดียวกับขนาน คุณหมุนเธรดได้มากเท่าที่คุณมี CPU และแบ่งงานของคุณอย่างสม่ำเสมอดังนั้นจึงดูแลงานที่ผูกกับ CPU ลองใช้ห้องสมุดนี้เพื่อโน้มน้าวตัวเองgithub.com/lehins/haskell-scheduler
lehins

คำตอบ:


2

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

import Control.Concurrent
import Control.Parallel.Strategies
import Data.Int
import System.Mem

lcgs :: Int32 -> [Int32]
lcgs = iterate lcg
  where lcg x = 1664525 * x + 1013904223

hasWaldo :: Int32 -> Bool
hasWaldo x = waldo `elem` take 40000000 (lcgs x)

waldo :: Int32
waldo = 0

main :: IO ()
main = do
  print $ or (map hasWaldo [1..100] `using` parList rseq)

สิ่งนี้ใช้กลยุทธ์รายการแบบขนานเพื่อค้นหาwaldo = 0(ซึ่งจะไม่พบ) ในผลลัพธ์ของสตรีม PRNG 100 รายการ 40 ล้านหมายเลขแต่ละรายการ รวบรวมและเรียกใช้:

ghc -threaded -O2 ParallelAny.hs
./ParallelAny +RTS -s -N4

และหมุดสี่แกนเป็นเวลาประมาณ 16 Falseวินาทีในที่สุดการพิมพ์ โปรดทราบในสถิติที่ประกายไฟ 100 ดวงทั้งหมดนั้นเป็น "แปลง" และดำเนินการจนเสร็จสิ้น:

SPARKS: 100(100 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled)

ตอนนี้เปลี่ยนwaldoเป็นค่าที่สามารถพบได้ในช่วงต้น:

waldo = 531186389   -- lcgs 5 !! 50000

และแก้ไขmainเพื่อให้เธรดมีชีวิตอยู่เป็นเวลา 10 วินาที:

main :: IO ()
main = do
  print $ or (map hasWaldo [1..100] `using` parList rseq)
  threadDelay 10000000

คุณจะสังเกตเห็นว่ามันพิมพ์Trueเกือบจะในทันที แต่ 4 คอร์ยังคงตรึงที่ CPU 100% (อย่างน้อยก็ซักพัก) แสดงให้เห็นว่าการคำนวณที่ไม่จำเป็นยังคงทำงานต่อไปและไม่ลัดวงจรเช่นเดียวกับที่คุณกลัว

แต่สิ่งต่าง ๆ จะเปลี่ยนไปถ้าคุณบังคับให้มีการรวบรวมขยะหลังจากได้รับคำตอบ:

main :: IO ()
main = do
  print $ or (map hasWaldo [1..100] `using` parList rseq)
  performGC
  threadDelay 10000000

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

SPARKS: 100(9 converted, 0 overflowed, 0 dud, 91 GC'd, 0 fizzled)

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

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

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