2011-01-31 19 views
8

क्या "Async.Parallel" निर्माण वास्तव में बहु-कोर सिस्टम पर गणनाओं को तेजी से बनाने में मदद करता है? क्या .NET TPL "कार्य" किसी भी तरह से शामिल हैं?क्या F # Async.Parallel गति की गणना करता है?

open System; 

let key = Console.ReadKey(true); 
let start = System.DateTime.Now 

let pmap f l = seq { for a in l do yield async {return f a} } |> Async.Parallel |> Async.RunSynchronously 
let map f l = seq {for a in l do yield f a} 

let work f l = 
match key.KeyChar with 
    | '1' -> pmap f l 
    | '2' -> Seq.toArray (map f l) 
    | _ -> [||] 

let result = work (fun x -> (x * x)/75) (seq { 1 .. 100000*3}) 
let endtime = DateTime.Now - start 

printfn "%A"endtime; 
let pause = Console.ReadKey(true); 

मुझे लगता है कि आप में से कुछ इसे सैद्धांतिक रूप से समझाएंगे, लेकिन मैं कुछ वास्तविक विश्व परीक्षणों की भी सराहना करता हूं।

+0

अनुक्रम 60000000 तक बढ़ाया गया है, यह 40 सेकंड या उसके बाद pmap में आउट-ऑफ-मेमोरी के साथ 10 सेकंड चलाता है। दोनों संस्करण मेरे दो कोरों में से केवल एक का उपयोग करते हैं। अब मुझे यह समझाने के लिए एक एफ # गुरु की आवश्यकता है :-) – TToni

उत्तर

9

pmap क्या कर रहा है 300,000 कार्य ऑब्जेक्ट्स की एक सूची बना रहा है, जो उन्हें समानांतर में चलाने के लिए व्यवस्था कर रहा है, और केवल तभी वास्तव में उन्हें समानांतर में चला रहा है। दूसरे शब्दों में, एक धागा 300,000 वस्तुओं को बनाकर और थ्रेड पूल पर कतार में बैठेगा। तभी वे निष्पादित करेंगे।

चूंकि आपका कार्य इतना छोटा (एक गुणा और विभाजित) है, कार्य बनाने का ओवरहेड, इसे शेड्यूल करना और इसके परिणाम को संभालना गणना को चलाने से कहीं अधिक है। इसका मतलब है कि इस ऑपरेशन के लिए async रूपक उपयुक्त है। इसके लिए PLINQ का उपयोग करना कहीं बेहतर है।

3

गणना के साथ यह सरल है, एक बेहतर तरीका केवल कुछ एसिंक थ्रेड्स (संभवतः प्रत्येक सीपीयू के लिए एक) बनाना है, और उसके बाद प्रत्येक आपके उत्तर का हिस्सा गणना करता है। जैसा कि गेबे ने उत्तर दिया, आप अपना पूरा समय कार्य वस्तुओं को बना रहे हैं।

एक योजना के इस प्रकार का उपयोग करना, मैं speedups कि CPUs की संख्या (सबसे मैं कोशिश की है 8 ... मुझे पता है यह हमेशा के लिए स्केल नहीं करेगा)

एक उपयोगिता लेखन के लिए बहुत बारीकी से पैमाने पर मिल ऐसा करने के लिए केवल PLINQ को कॉल करने से अधिक काम है, मुझे लगता है, लेकिन एक बार आपके पास pmap टाइप यूटिलिटी है, तो आप इसे आसानी से पुन: उपयोग कर सकते हैं।

12

पूरी तरह से सीपीयू-बाध्य कार्यों के लिए F # async का उपयोग केवल तभी काम करता है जब कार्य कुछ और जटिल ऑपरेशन करते हैं। यदि आप कोड को समानांतर करने का प्रयास कर रहे हैं जो कुछ बहुत आसान करता है, तो PLINQ (और टास्क समांतर लाइब्रेरी) का उपयोग करना बेहतर होता है, जो इस तरह की समस्याओं के लिए अधिक अनुकूलित होते हैं।

हालांकि, फिर भी, आपके पास एक मामूली मामला में तेजी लाने के लिए मुश्किल है। आप थोड़ा और इस के साथ प्रयोग करना चाहते हैं, तो आप इस कोशिश कर सकते हैं:

// Turn on timing in F# interactive 
#time 
let data = [| 1 .. 5000000*3 |] 

// Use standard 'map' function for arrays 
let result = Array.map (fun x -> (x * x)/75) data 
// Use optimized parallel version 
let result = Array.Parallel.map (fun x -> (x * x)/75) data 

ध्यान दें कि Array.map खुद का उपयोग कर एक बहुत अनुक्रम अभिव्यक्ति का उपयोग करते हैं और फिर एक सरणी के लिए परिणाम परिवर्तित करने की तुलना में तेजी है। आप मानचित्रण तुलना में अधिक जटिल आपरेशनों का उपयोग करना चाहते हैं, तो एफ # पॉवर Seq या List में उन लोगों के समान कार्यों के साथ PSeq मॉड्यूल शामिल हैं:

#r @"FSharp.PowerPack.Parallel.Seq.dll" 

data 
|> PSeq.map (fun a -> ...) 
|> PSeq.filter (fun a -> ...) 
|> PSeq.sort 
|> Array.ofSeq 

आप इस बारे में और अधिक पढ़ने के लिए चाहते हैं, तो मैं एक ब्लॉग श्रृंखला लिखा था के बारे में parallel programming in F# हाल ही में।

+5

तोमास यह उल्लेख करना भूल गया कि उन्होंने एफ # और समांतरता पर ब्लॉग पोस्ट की एक श्रृंखला लिखी है: http://tomasp.net/blog/fsharp-parallel-samples.aspx –

+0

लिंक उत्तर में प्रदान किया गया है मृत – Maslow

+0

@ मास्लो फिक्स्ड .. –

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