快捷搜索:  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

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

您可能还会对下面的文章感兴趣: