?
快捷搜索:  as  test  1111  test aNd 8=8  test++aNd+8=8  as++aNd+8=8  as aNd 8=8

愛博娛樂官網信譽:F中的異步及并行模式(1):并行CPU及IO計算

?

著末照樣忍不住翻譯文章了。這系列的文章討論的是F#中常見的異步及并行模式,作者為F#說話的主要設計者Don Syme。異步相關的編程是F#說話中最緊張的上風之一(我以致在斟酌“之一”兩個字能否去掉落)。F#是一門異常有特色的說話,是一門能夠坦蕩眼界,改變您編程思路的說話,它顛最后幾年設計以及多個預覽之后終于要正式露面了——此刻不上,更待何時。

先容

F#是一門并行(parallel)及相應式(reactive)說話。這個說法意味著一個F#法度榜樣可以存在多個進行中的運算(如應用.NET線程進行F#謀略),或是多個等待中的回應(如等待事故或消息的回調函數及代理工具)。

F#的異步表達式是簡化異步及相應式法度榜樣編寫的要領之一。在這篇及往后的文章中,我會探究一些應用F#進行異步編程的基礎要領──大年夜致說來,它們都是F#異步編程時應用的模式。這里我假設您已經掌握了async的基礎應用要領,如入門指南中的內容。

我們從兩個簡單的設計模式開始:CPU異步并行(Parallel CPU Asyncs)和I/O異步并行(Paralle I/O Asyncs)。

本系列的第2部分描述了若何從異步謀略或后臺謀略單元中得到結果。

第3部分則描述了F#中輕量級的,相應式的,各自自力的代理工具。

模式1:CPU異步并行

首先來懂得第一個模式:CPU異步并行,這意味著并行地開展一系列的CPU密集型謀略。下面的代碼謀略的是斐波那契數列,它會將這些謀略進行并行地調配:

let rec fib x = if x then 1 else fib(x-1) + fib(x-2)

let fibs =

Async.Parallel [ for i in 0..40 -> async { return fib(i) } ]

|> Async.RunSynchronously

結果是:

val fibs : int array =

[|1; 1; 2; 3; 5; 8; 13; 21; 34; 55; 89; 144; 233; 377; 610; 987; 1597; 2584;

4181; 6765; 10946; 17711; 28657; 46368; 75025; 121393; 196418; 317811;

514229; 832040; 1346269; 2178309; 3524578; 5702887; 9227465; 14930352;

24157817; 39088169; 63245986; 102334155|]

上面的代碼展示了并行CPU異步謀略模式的要素:

“async { … }”用于指定一系列的CPU義務。

這些義務應用Async.Parallel進行fork-join式的組合。

在這里,我們應用Async.RunSynchronously措施來履行組合后的義務,這會啟動一個異步義務,并同步地等待其著末結果。您可以應用這個模式來完成各類CPU并行(例如對矩陣乘法進行劃分和并行謀略)或是批量處置懲罰義務。

模式2:I/O異步并行

現在我們已經展示了在F#中進行CPU密集型并行編程的要領。F#異步編程的重點之一,就是可以用相同的要領進行CPU和I/O密集型的謀略。這就是我們的第二種模式:I/O異步并行,即同時開展多個I/O操作(也被稱為overlapped I/O)。例如下面的代碼便并行地哀求多個Web頁面,并相應每個哀求的回覆,再返收受吸網絡到的結果。

open System

open System.Net

open Microsoft.FSharp.Control.WebExtensions

let http url =

async { let req =WebRequest.Create(Uri url)

use! resp = req.AsyncGetResponse()

use stream = resp.GetResponseStream()

use reader = new StreamReader(stream)

let contents = reader.ReadToEnd()

return contents }

let sites = ["http://www.bing.com";

"http://www.google.com";

"http://www.yahoo.com";

"http://www.search.com"]

let htmlOfSites =

Async.Parallel [for site in sites -> http site ]

|> Async.RunSynchronously

上面的代碼示例展示了I/O異步并行模式的根基:

“async { … }”用于編寫義務,此中包孕了一些異步I/O。

這些義務應用Async.Parallel進行fork-join式的組合。

在這里,我們應用Async.RunSynchronously措施來履行組合后的義務,這會啟動一個異步義務,并同步地等待其著末結果。

應用let!(或與它類似的資本開釋指令use!)是進行異步操作的根基措施。例如:

let! resp = req.AsyncGetResponse()

上面這行代碼會“相應”一個HTTP GET操作所獲得的回覆,即async { … }在AsyncGetResponse操作完成之后的部分。然而,在等待相應的歷程中并不會壅閉任何.NET或操作系統的線程:只有活動的CPU密集型運算會應用下層的.NET或操作系統線程。與此不合,等待中的相應操作(例如回調函數,事故處置懲罰法度榜樣和代理工具)資本占用異常少,險些只相稱于一個注冊好的工具而已。是以,您可以同時擁稀有千個以致數百萬個等待中的相應操作。例如,一個范例的GUI利用法度榜樣會注冊一些事故處置懲罰法度榜樣,而一個范例Web爬蟲會為每個發出的哀求注冊一個回調函數。

在上面的代碼中,我們應用了“use!”而不是“let!”,這表示Web哀求相關的資本會在變量越過字面的感化域之后獲得開釋。

I/O并行的美妙之處在于其伸縮性。在多核的情況下,假如您可以充分使用謀略資本,則平日會得到2倍、4倍以致8倍的機能前進。而在I/O并行編程中,您可以同時進行成百上千的I/O操作(不過實際的并行效果還要取決于您的操作系統和收集連接狀況),這意味著10倍、100倍、1000倍以致更多的機能增強──而這統統在一臺單核的機械上也可以實現。例如,這里有一個應用F#異步功能的示例,而終極它們可以在一個IronPython利用法度榜樣中應用。

許多今世利用法度榜樣都是I/O密集型利用,是以這些設計模式在實踐中都有很緊張的意義。

始于GUI線程,終于GUI線程

這兩個設計模式有個緊張的變更,這就是應用Async.StartWithContinuations來代替Async.RunSynchronously措施。在一個并行操作開啟之后,您可以指定三個函數,分手在它成功、掉敗或取消時調用。

對付諸如“我想要得到一個異步操作的結果,但我不能應用RunSynchronously措施”之類的問題,您便應該斟酌:

應用let!(或use!)把這個異步操作作為更大年夜的異步義務的一部分,或者

應用Async.StartWithContinuations措施履行異步操作

在那些必要在GUI線程上提議異步操作的場景中,Async.StartWithContinuations措施尤其有用。由于,您不會是以壅閉住GUI線程,而且可以在異步操作完成后直接進行GUI的更新。例如,在F# JAOO Tutorial的BingTranslator示例中便應用了這個做法──您可以在本文結尾瀏覽它的完備代碼,不過這里最值得關注的部分則是在點擊“Translate”按鈕之后發生的工作:

button.Click.Add(fun args ->

let text = textBox.Text

translated.Text "Translating..."

let task =

async { let! languages = httpLines languageUri

let! fromLang = detectLanguage text

let! results = Async.Parallel [for lang in languages -> translateText 愛博娛樂官網信譽(text, fromLang, lang)]

return (fromLang,results) }

Async.StartWithContinuations(

task,

(fun (fromLang,results) ->

for (toLang, translatedText) in results do

translated.Text "\r\n%s --> %s: \"%s\"" fromLang toLang translatedText),

(fun exn -> MessageBox.Show(sprintf "An error occurred: %A" exn) |> ignore),

(fun cxn -> MessageBox.Show(sprintf "A cancellation error ocurred: %A" cxn) |> ignore)))

高亮的部分,尤其是在async塊里的部分,展示了應用Async.Parallel將一種說話并行地翻譯成多種說話的做法。這個異步組合操作由 Async.StartWithContinuations提議,它會在碰到第一個I/O操作時急速返回(譯注:存疑,為什么是在趕上I/O操作才返回?),并指定了三個函數,分手在異步操作的成功,掉敗或取消時調用。以下是義務完成后的愛博娛樂官網信譽截圖(不過在此不包管翻譯的準確性……):

Async.StartWithContinuations有一個緊張的特點:假如異步操作由GUI線程提議(例如一個 SynchronizationContext.Current不為null的線程),那么操作完成后的回調函數也是在GUI線程中調用的。這使GUI更新操作變的十分安然。F#異步類庫容許您組合多個I/O義務,并在GUI線程中直接應用,而無需您親身從后臺線程中更新GUI元素。在今后的文章中我們會進行更具體地解釋。

關于Async.Parallel事情要領:

在履行時,由Async.Parallel組合而成的異步操作會經由過程一個等待謀略的行列步隊來慢慢提議。與大年夜部分進行異步處置懲罰的類庫一樣,它在內部應用的是QueueUserWorkItem措施。當然,我們也有法子應用分離的行列步隊,在今后的文章中我們會進行一些評論爭論。

Async.Parallel措施并沒有什么神奇之處,您也完全可以應用Microsoft.FSharp.Control.Async類庫中的其他原語來定義您自己的異步組合要領──例如Async.StartChild措施。我們會在今后的文章中評論爭論這個話題。

更多示例

在F# JAOO Tutorial包孕多個應用這些模式的示例代碼:

BingTranslator.fsx與BingTranslatorShort.fsx:應用F#調用REST API,它們與其他基于Web的HTTP辦事的調用要領十分類似。文末包孕了示例的完備代碼。

AsyncImages.fsx:并行磁盤I/O及圖像處置懲罰。

PeriodicTable.fsx:調用一個Web辦事,并行地獲取原子質量。

本文模式的限定

上文先容的兩個并行模式有一些限定。很顯著,應用Async.Parallel天生的異步操作在履行時十分“恬靜”──比方說,它們無法返回進度或部分的結果。為此,我們必要構建一個更為“富厚”的工具,它會在部分操作完成之后觸發一些事故。在今后的文章中我們會來關注這樣的設計模式。

此外,Async.Parallel只能處置懲罰固定命量的義務。在愛博娛樂官網信譽今后的文章中,我們會碰到很多一邊處置懲罰一邊天生義務的環境。換個要領來看,即Async.Parallel無法處置懲罰即時得到愛博娛樂官網信譽的消息──例如,除了取消義務之外,一個代理工具的事情進度是可以獲得節制的。

總結

CPU異步并行與I/O異步并行,是F#異步編程中最為簡單的兩種設計模式,而簡單的事物每每也是異常緊張而強大年夜的。請留意,兩種模式的不合之處,僅僅在于I/O并行應用了包孕了I/O哀求的async塊,以及一些額外的CPU義務,如創建哀求工具及后續處置懲罰。

在往后的文章里,我們會關注F#中其他一些并行及相應式編程方面的設計要領,包括:

從GUI線程中提議異步操作

定義輕量級異步代理工具

應用async定義后臺事情法度榜樣

應用async構建.NET義務

應用async調用.NET的APM模式

取消異步操作

BingTranslator代碼示例

以下是BingTranslator的示例代碼,在運行時您必要申請一個Live API 1.1 AppID。請留意,這個示例必要根據Bing API 2.0進行適當調劑,至少在2.0中已經不包孕這里的說話檢測API了──不過這些代碼仍舊是不錯的示例:

open System

open System.Net

open System.IO

open System.Drawing

open System.Windows.Forms

open System.Text

/// A standard helper to read all the lines of a HTTP request. The actual read of the lines is

/// synchronous once the HTTP response has been received.

let httpLines (uri:string) =

async { let request = WebRequest.Create uri

use! response = request.AsyncGetResponse()

use stream = response.GetResponseStream()

use reader = new StreamReader(stream)

let lines = [ while not reader.EndOfStream do yield reader.ReadLine() ]

return lines }

type System.Net.WebRequest with

/// An extension member to write content into an WebRequest.

/// The write of the content is synchronous.

member req.WriteContent (content:string) =

let bytes = Encoding.UTF8.GetBytes content

req.ContentLength use stream = req.GetRequestStream()

stream.Write(bytes,0,bytes.Length)

/// An extension member to read the content from a response to a WebRequest.

/// The read of the content is synchronous once the response has been received.

member req.AsyncReadResponse () =

async { use! response = req.AsyncGetResponse()

use responseStream = response愛博娛樂官網信譽.GetResponseStream()

use reader = new StreamReader(responseStream)

return reader.ReadToEnd() }

#load @"C:\fsharp\staging\docs\presentations\2009-10-04-jaoo-tutorial\BingAppId.fs"

//let myAppId = "please set your Bing AppId here"

/// The URIs for the REST service we are using

let detectUri= "http://api.microsofttranslator.com/V1/Http.svc/Detect?appId=" + myAppId

let translateUri= "http://api.microsofttranslator.com/V1/Http.svc/Translate?appId=" + myAppId + "&"

let languageUri= "http://api.microsofttranslator.com/V1/Http.svc/GetLanguages?appId=" + myAppId

let languageNameUri = "http://api.microsofttranslator.com/V1/Http.svc/GetLanguageNames?appId=" + myAppId

/// Create the user interface elements

let form= new Form (Visible=true, TopMost=true, Height=500, Width=600)

let textBox= new TextBox (Width=450, Text="Enter some text", Font=new Font("Consolas", 14.0F))

let button= new Button (Text="Translate", Left = 460)

let translated = new TextBox (Width = 590, Height = 400, Top = 50, ScrollBars = ScrollBars.Both, Multiline = true, Font=new Font("Consolas", 14.0F))

form.Controls.Add textBox

form.Controls.Add button

form.Controls.Add translated

/// An async method to call the language detection API

let detectLanguage text =

async { let request = WebRequest.Create (detectUri, Method="Post", ContentType="text/plain")

do request.WriteContent text

return! request.AsyncReadResponse() }

/// An async method to call the text translation API

let translateText (text, fromLang, toLang) =

async { let uri = sprintf "%sfrom=%s&to=%s" translateUri fromLang toLang

let request = WebRequest.Create (uri, Method="Post", ContentType="text/plain")

request.WriteContent text

let! translatedText = request.AsyncReadResponse()

return (toLang, translatedText) }

button.Click.Add(fun args ->

let text = textBox.Text

translated.Text "Translating..."

let task =

async { /// Get the supported languages

let! languages = httpLines languageUri

/// Detect the language of the input text. This could be done in parallel with the previous step.

let! fromLang = detectLanguage text

/// Translate into each language, in parallel

let! results = Async.Parallel [for lang in languages -> translateText (text, fromLang, lang)]

/// Return the results

return (fromLang,results) }

/// Start the task. When it completes, show the results.

Async.StartWithContinuations(

task,

(fun (fromLang,results) ->

for (toLang, translatedText) in results do

translated.Text "\r\n%s --> %s: \"%s\"" fromLang toLang translatedText),

(fun exn -> MessageBox.Show(sprintf "An error occurred: %A" exn) |> ignore),

(fun cxn -> MessageBox.Show(sprintf "A cancellation error ocurred: %A" cxn) |> ignore)))

原文:Async and Parallel Design Patterns in F#: Parallelizing CPU and I/O Computations

轉自:http://www.cnblogs.com/JeffreyZhao/archive/2010/03/03/async-and-parallel-design-patterns-in-fsharp-1-parallelizing-cpu-and-io-computations.html

免責聲明:以上內容源自網絡,版權歸原作者所有,如有侵犯您的原創版權請告知,我們將盡快刪除相關內容。

您可能還會對下面的文章感興趣:

快三平台开户