2012-10-28 31 views
9

में अनुक्रमण आईओ कार्यों मैं एक समारोह है कि एक आईओ कार्रवाई देता है,समानांतर

f :: Int -> IO Int 

मैं तर्क के एक से अधिक मान के लिए समानांतर में इस समारोह की गणना करना चाहते हैं। मेरे अनुभवहीन कार्यान्वयन इस प्रकार है:

import Control.Parallel.Strategies 

vals = [1..10] 
main = do 
     results <- mapM f vals 
     let results' = results `using` parList rseq 
     mapM_ print results' 

इस के लिए मेरे तर्क है कि पहले mapMresults के प्रकार IO [Int] के बारे में कुछ बांधता है, results' निहित सूची के लिए एक समानांतर रणनीति लागू होता है, और अंत में mapM_ द्वारा वास्तविक मान का अनुरोध करता था उन्हें प्रिंट करना - लेकिन मुद्रित करने के लिए क्या पहले से ही समानांतर में चमक रहा है, इसलिए कार्यक्रम समानांतर होना चाहिए।

खुश होने के बाद यह वास्तव में मेरे सभी सीपीयू का उपयोग करता है, मैंने देखा है कि कार्यक्रम किसी भी आरटीएस झंडे के बिना +RTS -N8 के साथ चलते समय कम प्रभावी (दीवार घड़ी के समय में) है। एकमात्र स्पष्टीकरण मैं सोच सकता हूं कि पहला mapM अनुक्रम करना है - यानी प्रदर्शन - पहले से ही सभी आईओ क्रियाएं, लेकिन इससे अप्रभावीता नहीं होती है, लेकिन N8 निष्पादन को समानांतर के रूप में प्रभावी बनाते हैं, क्योंकि सभी काम है मास्टर थ्रेड द्वारा किया गया। +RTS -N8 -s के साथ प्रोग्राम चलाने से SPARKS: 36 (11 converted, 0 overflowed, 0 dud, 21 GC'd, 4 fizzled) उत्पन्न होता है, जो निश्चित रूप से इष्टतम नहीं है, लेकिन दुर्भाग्यवश मैं इसका कोई अर्थ नहीं उठा सकता।

मुझे लगता है कि मुझे हास्केल समांतरता या आईओ मोनड के आंतरिक में शुरुआती कदम उठाने वाले पत्थरों में से एक मिला है। मैं क्या गलत कर रहा हूं?

पृष्ठभूमि जानकारी: f n एक ऐसा फ़ंक्शन है जो प्रोजेक्ट यूलर समस्या n के लिए समाधान देता है। चूंकि उनमें से कई को पढ़ने के लिए डेटा है, इसलिए मैंने परिणाम आईओ मोनड में डाल दिया। यह कैसे की तरह लग रहे हो सकता है का एक उदाहरण

-- Problem 13: Work out the first ten digits of the sum of one-hundred 50-digit numbers. 

euler 13 = fmap (first10 . sum) numbers 
     where 
      numbers = fmap (map read . explode '\n') $ readFile "problem_13" 
      first10 n 
        | n < 10^10 = n -- 10^10 is the first number with 11 digits 
        | otherwise = first10 $ n `div` 10 

पूर्ण फ़ाइल here पाया जा सकता है (यह थोड़ा लंबा है, लेकिन पहले कुछ "यूलर एक्स" कार्यों के लिए पर्याप्त प्रतिनिधि होना चाहिए), मुख्य फ़ाइल मैं कहाँ करना है समांतरता this one है।

+0

अधिक देखे बिना निदान करना मुश्किल है। यदि आप इसे '+ आरटीएस-एस-एन' के साथ चलाते हैं, तो परिवर्तित/छिड़काव/चक्करदार स्पार्क के आंकड़े क्या हैं? और क्या 'एफ एन' एक थंक लौटाता है जिसे वास्तव में स्पार्क किया जा सकता है? –

+0

@ डैनियल फिशर मैं पूरी फ़ाइल पोस्ट करने में थोड़ा संकोच कर रहा था क्योंकि यह काफी लंबा है (न्यूनतम उदाहरण और ऐसे)। मैंने सोचा कि मेरी गलती समानांतर कोड में थी, इसलिए मैंने अपने प्रश्न में उस पर ध्यान केंद्रित किया। मैंने अब एक नया पैराग्राफ जोड़ा है, और '-s' आंकड़े भी जोड़े हैं (जो भयानक हैं)। – David

+0

मुझे यकीन नहीं है कि वास्तव में I/O करने वाले लोग इसे नष्ट कर देंगे, लेकिन शुद्ध लोगों के लिए (डेटा का उपयोग नहीं करते हैं।परमिट ', क्योंकि मेरे पास यह इंस्टॉल नहीं है), मुझे' parListChunk 'के बजाय' parListChunk k' का उपयोग करके एक गति (और अधिक रूपांतरित स्पार्क) मिला है - यहां तक ​​कि 'parListChunk 1' के साथ भी, हालांकि वह' parlist' 'कहता है। –

उत्तर

7

रणनीतियां शुद्ध गणना के समानांतर निष्पादन के लिए हैं। यदि यह वास्तव में अनिवार्य है कि आपका fIO मान देता है, तो इसके बजाय async पैकेज का उपयोग करने पर विचार करें। यह IO क्रियाओं को एक साथ चलाने के लिए उपयोगी संयोजक प्रदान करता है।

आपके उपयोग के मामले के लिए, mapConcurrently उपयोगी दिखता है:

import Control.Concurrent.Async 

vals = [1..10] 
main = do 
    results <- mapConcurrently f vals 
    mapM_ print results 

(मैं हालांकि परीक्षण नहीं किया है, क्योंकि मैं नहीं जानता कि क्या आपके f ठीक है।)

+0

यदि आप इसे * परीक्षण करना चाहते हैं, तो मैंने पूर्ण जोड़ा है मेरी पोस्ट के अंत में लिपि। यदि नहीं: Async एक ही प्रदर्शन हिट से पीड़ित है, लेकिन यह एक ऐसा पैकेज है जो बहुत ही आशाजनक दिखता है कि मैंने अब तक उपेक्षित किया है, इसलिए बहुत बहुत धन्यवाद! – David

2

parallel-io पैकेज की कोशिश करो। यह आपको mapM_ को parallel_ में बदलने की अनुमति देता है।

संबंधित मुद्दे