2013-04-07 6 views
5

में ग्लोबल स्टेट और असिंक वर्कफ़्लोज़ F # में एसिंक्रोनस वर्कफ़्लो को चित्रित करने के लिए उपयोग किया जाने वाला एक आम उदाहरण समानांतर में एकाधिक वेबपृष्ठों को पुनर्प्राप्त कर रहा है। http://en.wikibooks.org/wiki/F_Sharp_Programming/Async_Workflows कोड मामले में यहाँ दिखाया गया है भविष्य में कड़ी परिवर्तन: ऐसा ही एक उदाहरण पर दिया जाता हैएफ #

open System.Text.RegularExpressions 
open System.Net 

let download url = 
    let webclient = new System.Net.WebClient() 
    webclient.DownloadString(url : string) 

let extractLinks html = Regex.Matches(html, @"http://\S+") 

let downloadAndExtractLinks url = 
    let links = (url |> download |> extractLinks) 
    url, links.Count 

let urls = 
    [@"http://www.craigslist.com/"; 
    @"http://www.msn.com/"; 
    @"http://en.wikibooks.org/wiki/Main_Page"; 
    @"http://www.wordpress.com/"; 
    @"http://news.google.com/";] 

let pmap f l = 
    seq { for a in l -> async { return f a } } 
    |> Async.Parallel 
    |> Async.Run 

let testSynchronous() = List.map downloadAndExtractLinks urls 
let testAsynchronous() = pmap downloadAndExtractLinks urls 

let time msg f = 
    let stopwatch = System.Diagnostics.Stopwatch.StartNew() 
    let temp = f() 
    stopwatch.Stop() 
    printfn "(%f ms) %s: %A" stopwatch.Elapsed.TotalMilliseconds msg temp 

let main() = 
    printfn "Start..." 
    time "Synchronous" testSynchronous 
    time "Asynchronous" testAsynchronous 
    printfn "Done." 

main() 

क्या मैं जानना चाहूंगा कि कैसे एक इस तरह के एक नेटवर्क कनेक्शन के नुकसान के रूप में वैश्विक स्थिति के बदलावों को संभालने की आवश्यकता है? क्या ऐसा करने का कोई शानदार तरीका है?

Async.Parallel कॉल करने से पहले नेटवर्क की स्थिति की जांच कर सकता है, लेकिन निष्पादन के दौरान राज्य बदल सकता है। मान लीजिए कि क्या करना चाहता था निष्पादन रोकना था जब तक नेटवर्क विफल होने की बजाय फिर से उपलब्ध नहीं था, क्या ऐसा करने का एक कार्यात्मक तरीका है?

उत्तर

4

सबसे पहले, वहाँ उदाहरण के साथ एक मुद्दा है - यह Async.Parallel का उपयोग करता समानांतर लेकिन आपरेशन के लिए खुद को अतुल्यकालिक रूप में लागू नहीं कर रहे हैं में एक से अधिक आपरेशन चलाने के लिए है, इसलिए इस सूत्र में धागे की अत्यधिक संख्या को अवरुद्ध से नहीं बचेगा पूल।

असीमित। कोड पूरी तरह से अतुल्यकालिक बनाने के लिए, download और downloadAndExtractLinks कार्यों भी अतुल्यकालिक होना चाहिए, ताकि आप WebClient की AsyncDownloadString उपयोग कर सकते हैं:

let asyncDownload url = async { 
    let webclient = new System.Net.WebClient() 
    return! webclient.AsyncDownloadString(System.Uri(url : string)) } 

let asyncDownloadAndExtractLinks url = async { 
    let! html = asyncDownload url 
    let links = extractLinks html 
    return url, links.Count } 

let pmap f l = 
    seq { for a in l -> async { return! f a } } 
    |> Async.Parallel 
    |> Async.RunSynchronously 

पुनः प्रयास किया जाएगा। अब, प्रश्न का उत्तर देने के लिए - नेटवर्क विफलता जैसी त्रुटियों को संभालने के लिए कोई अंतर्निहित तंत्र नहीं है, इसलिए आपको इस तर्क को स्वयं लागू करने की आवश्यकता होगी। सही दृष्टिकोण क्या है आपकी स्थिति पर निर्भर करता है। एक आम तरीका ऑपरेशन को कई बार फिर से प्रयास करना है और अपवाद फेंकना है अगर यह सफल नहीं होता है उदा। 10 बार। आप एक आदिम है कि अन्य अतुल्यकालिक कार्यप्रवाह लेता है के रूप में लिख सकते हैं:

let testAsynchronous() = 
    pmap (asyncRetry 10 downloadAndExtractLinks) urls 

साझा राज्य:

let rec asyncRetry times op = async { 
    try 
    return! op 
    with e -> 
    if times <= 1 then return (reraise e) 
    else return! asyncRetry (times - 1) op } 

तो फिर तुम एक कार्यप्रवाह कि डाउनलोड पुनः प्रयास करता है 10 बार के निर्माण के लिए मुख्य कार्य बदल सकते हैं। एक और समस्या यह है कि Async.Parallel केवल एक बार सभी डाउनलोड पूर्ण होने के बाद ही लौट आएगा (यदि कोई दोषपूर्ण वेबसाइट है, तो आपको प्रतीक्षा करनी होगी)। यदि आप परिणाम वापस दिखाना चाहते हैं, तो आपको कुछ और परिष्कृत की आवश्यकता होगी।

ऐसा करने का एक अच्छा तरीका एफ # एजेंट का उपयोग करना है - एक एजेंट बनाएं जो अब तक प्राप्त परिणामों को संग्रहीत करता है और दो संदेशों को संभाल सकता है - जो नया परिणाम जोड़ता है और दूसरा जो वर्तमान स्थिति देता है। फिर आप कई एसिंक कार्यों को शुरू कर सकते हैं जो परिणाम को एजेंट को भेजेंगे और, एक अलग async वर्कफ़्लो में, आप वर्तमान स्थिति की जांच करने के लिए मतदान का उपयोग कर सकते हैं (और उदाहरण के लिए उपयोगकर्ता इंटरफ़ेस अपडेट करें)।

मैंने डेवलपर फ़्यूज़न के लिए MSDN series about agents और twoarticles लिखा है जिसमें एफ # एजेंटों के साथ बहुत सारे कोड नमूने हैं।

+0

टॉम, जबकि मुझे वास्तव में एफ # एजेंट पसंद हैं, मुझे नहीं लगता कि यह हास्केल जैसे कार्यात्मक प्रोग्रामिंग कैसे है। ऐसा लगता है कि ऐसा करने के लिए राज्य (दस्केल में आईओ मोनैड) का इलाज किसी कार्य को पारित करने के लिए किया जाता है, यह राज्य को एजेंटों के बीच गुजरने वाले संदेश के साथ "एजेंटों" के साथ कई एजेंटों द्वारा उत्परिवर्तित करने के लिए व्यवहार करता है। – JonnyBoats

+2

एजेंटों का उपयोग करना निश्चित रूप से कार्यात्मक प्रोग्रामिंग नहीं है जैसे हास्केल।मैं ईमानदारी से नहीं सोचता कि समस्या के लिए पूरी तरह से कार्यात्मक समाधान सुरुचिपूर्ण और उपयोगी हैं। संदेश-पासिंग कॉन्सुरेंसी एक और उपयोगी प्रतिमान है जो F # में उपलब्ध है - और मुझे लगता है कि यह समवर्ती प्रक्रियाओं के लिए वास्तव में अच्छी तरह से काम करता है जिसे समन्वय करने की आवश्यकता है। –

+0

यह कुछ ऐसा है जो मैं इस समय अपने सिर को पाने की कोशिश कर रहा हूं। हास्केल की पसंद के माध्यम से एफपी की खोज करने के बाद (लेकिन अभी भी इसमें बहुत अनुभवहीन), प्रलोभन F # में पूरी तरह से शुद्ध दृष्टिकोण के लिए जाना है। प्रतिमानों का सही मिश्रण ढूंढना मुझे लगता है कि एक लंबी सीखने की प्रक्रिया होगी। – shambulator