日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢(xún)
選擇下列產(chǎn)品馬上在線(xiàn)溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
詳解F#異步及并行模式中的輕量級(jí)代理

F#目前還有些待字閨中的意思,不過(guò)隨著大家對(duì)F#了解的加深。希望更多的程序員能運(yùn)用好F#。在此之前,我們?cè)鴪?bào)道過(guò)《詳解F#異步及并行模式中的并行CPU及I/O計(jì)算》

創(chuàng)新互聯(lián)自2013年創(chuàng)立以來(lái),是專(zhuān)業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項(xiàng)目成都網(wǎng)站建設(shè)、成都網(wǎng)站設(shè)計(jì)網(wǎng)站策劃,項(xiàng)目實(shí)施與項(xiàng)目整合能力。我們以讓每一個(gè)夢(mèng)想脫穎而出為使命,1280元扶余做網(wǎng)站,已為上家服務(wù),為扶余各地企業(yè)和個(gè)人服務(wù),聯(lián)系電話(huà):028-86922220

在本系列的第3部分中,我們會(huì)來(lái)探索F#中輕量級(jí)的,交互式的代理,以及與代理有關(guān)的一些模式,包括“隔離的內(nèi)部狀態(tài)”。(譯注:由于原文較長(zhǎng),因此譯文分為兩段,目前是第一段,講解了F#中異步代理的基本使用方式。)

第1部分描述了F#作為一個(gè)并行及異步語(yǔ)言,是如何支持輕量級(jí)的響應(yīng)操作,并給出了CPU異步并行和I/O異步并行兩種模式。

第2部分描述了如何從異步計(jì)算或后臺(tái)計(jì)算單元中獲得結(jié)果。

模式4:您的第一個(gè)代理

我們來(lái)觀察您所創(chuàng)建的第一個(gè)異步代理:

 
 
 
  1. type Agent<'T> = MailboxProcessor<'T>
  2. let agent =
  3.    Agent.Start(fun inbox ->
  4.      async { while true do
  5.                let! msg = inbox.Receive()
  6.                printfn "got message '%s'" msg } )

這個(gè)代理不斷地異步等待消息,并將它們打印出來(lái)。在這段代碼中,每個(gè)消息都是一個(gè)字符串,且agent的類(lèi)型是:

agent.Post "hello!"這便會(huì)打印出:

got message 'hello!'也可以這樣發(fā)送多條消息:

for i in 1 .. 10000 do
   agent.Post (sprintf "message %d" i)

這樣便可以打印出10000條消息。

您可以認(rèn)為每個(gè)代理對(duì)象都包含一個(gè)消息隊(duì)列(或管道),并在消息到達(dá)時(shí)進(jìn)行響應(yīng)。一個(gè)委托一般都使用異步的循環(huán)等待來(lái)消息并進(jìn)行處理。如在上面的例子中,代理使用while循環(huán)進(jìn)行處理。

許多讀者可能已經(jīng)對(duì)代理頗為熟悉了。如Erlang,它便是基于代理設(shè)計(jì)的(在那里被稱(chēng)為進(jìn)程)。而不久之前,一個(gè)基于.NET平臺(tái)的實(shí)驗(yàn)性的孵化型語(yǔ)言,Axum,也注重了基于代理編程的重要性。Axum與F#中的代理設(shè)計(jì)相互影響,而其他包含輕量級(jí)線(xiàn)程的語(yǔ)言也強(qiáng)調(diào)了基于代理的組合與設(shè)計(jì)。

上面的例子一開(kāi)始創(chuàng)建了一個(gè)類(lèi)型的縮寫(xiě):Agent,它代表了F#類(lèi)庫(kù)中基于內(nèi)存的代理類(lèi)型“MailboxProcessor”。如果您愿意的話(huà)也可以使用這個(gè)完整的名字,不過(guò)我更喜歡簡(jiǎn)單的命名。

您的第一批10萬(wàn)個(gè)代理

代理對(duì)象非常輕量,這是因?yàn)樗贔#的異步編程模型。例如,您可以在一個(gè).NET進(jìn)程中創(chuàng)建成百上千,甚至更多個(gè)代理。例如,我們來(lái)創(chuàng)建10萬(wàn)個(gè)簡(jiǎn)單的代理對(duì)象:

 
 
 
  1. let agents =
  2.     [ for i in 0 .. 100000 ->
  3.        Agent.Start(fun inbox ->
  4.          async { while true do
  5.                    let! msg = inbox.Receive()
  6.                    if i % 10000 = 0 then
  7.                        printfn "agent %d got message '%s'" i msg } ) ]

您可以這樣向每個(gè)代理對(duì)象發(fā)送消息:

for agent in agents do
    agent.Post "ping!每第1萬(wàn)個(gè)代理對(duì)象會(huì)在收到消息時(shí)打印信息。這個(gè)代理集合在處理消息時(shí)非常迅速,只要幾秒鐘時(shí)間。代理和內(nèi)存中的消息處理非常快。

很顯然,代理并不與.NET線(xiàn)程直接對(duì)應(yīng)──您不可能在單個(gè)應(yīng)用程序中創(chuàng)建10萬(wàn)的線(xiàn)程(在32位操作系統(tǒng)中,即便1000個(gè)線(xiàn)程也已經(jīng)太多了)。相反,在代理等待消息時(shí),它實(shí)際上只是表現(xiàn)為一個(gè)回調(diào)函數(shù),一些對(duì)象分配,以及代理所引用的閉包等等。在收到消息之后,代理的工作會(huì)在一個(gè)線(xiàn)程池(默認(rèn)便是.NET線(xiàn)程池)中分配并執(zhí)行。

盡管需要10萬(wàn)個(gè)代理的情況并不多見(jiàn),不過(guò)2000多個(gè)代理倒是很正常的。接下來(lái)我們便會(huì)看到這樣一些例子。

高伸縮的Web服務(wù)器處理請(qǐng)求

在F#編程中,異步代理的思想其實(shí)是一種在多個(gè)環(huán)境中反復(fù)出現(xiàn)的設(shè)計(jì)模式。在F#中,我們經(jīng)常使用“代理”這個(gè)詞表示一種隨時(shí)發(fā)生的,特別是通過(guò)循環(huán),或是處理消息,或是產(chǎn)生結(jié)果的異步計(jì)算。

例如,在以后的文章中,我們會(huì)來(lái)關(guān)注如何使用F#構(gòu)建伸縮性強(qiáng)的TCP或HTTP服務(wù)器應(yīng)用程序,并將它們部署到EC2或是Windows Azure中去。這里我們打算用“股票服務(wù)器”作為例子,它接受TCP或HTTP連接,并向客戶(hù)端返回一系列的股票信息。每個(gè)客戶(hù)端會(huì)每隔一秒鐘收到一條股票信息。這個(gè)服務(wù)最終會(huì)以單個(gè)URL或REST API的形式發(fā)布。

在實(shí)現(xiàn)時(shí),我們?yōu)槊總€(gè)客戶(hù)端請(qǐng)求分配一個(gè)異步代理(由于只是演示,我們?cè)谶@里便不斷地寫(xiě)入相同的AAPL股票信息):

 
 
 
  1. open System.Net.Sockets
  2. /// serve up a stream of quotes
  3. let serveQuoteStream (client: TcpClient) = async {
  4.     let stream = client.GetStream()
  5.     while true do
  6.         do! stream.AsyncWrite( "AAPL 200.38"B )
  7.         do! Async.Sleep 1000.0 // sleep one second}

每個(gè)代理會(huì)一直運(yùn)行到客戶(hù)端連接斷開(kāi)。因?yàn)榇矸浅]p量,因此這個(gè)股票服務(wù)能夠在一臺(tái)機(jī)器上支持?jǐn)?shù)千個(gè)并發(fā)連接(如果使用云托管服務(wù)則會(huì)有更好的伸縮性)。而同一時(shí)刻會(huì)出現(xiàn)多少個(gè)代理對(duì)象則取決于客戶(hù)端的數(shù)量。

上面的例子演示了使用F#進(jìn)行網(wǎng)絡(luò)編程是多么的方便──網(wǎng)絡(luò)協(xié)議在此變成了基于異步代理的數(shù)據(jù)流讀寫(xiě)。在以后的文章中我們會(huì)觀察更多使用F#進(jìn)行伸縮性強(qiáng)的TCP/HTTP編程。

代理與隔離狀態(tài)(命令式)

F#代理編程的一個(gè)優(yōu)秀的關(guān)鍵之處便是其隔離性。隔離性則意味著資源“歸屬”與某個(gè)特定的代理,而不會(huì)暴露給其他代理。因此,獨(dú)立狀態(tài)對(duì)并發(fā)的訪(fǎng)問(wèn)及數(shù)據(jù)競(jìng)爭(zhēng)是一種良好的保護(hù)。

在F#中,異步代理的獨(dú)立性直接表現(xiàn)為文法上的作用域。例如,下面的代碼使用一個(gè)字典來(lái)累計(jì)發(fā)送至代理對(duì)象的不同消息的次數(shù)。內(nèi)部的字典在文法上是異步代理私有的,因此我們無(wú)法在代理外部對(duì)字典進(jìn)行讀寫(xiě)。這意味著字典的可變狀態(tài)實(shí)際上是被隔離的,代理保證了對(duì)它的非并發(fā)的安全訪(fǎng)問(wèn)。

 
 
 
  1. type Agent<'T> = MailboxProcessor<'T>
  2. open System.Collections.Generic
  3. let agent =
  4.    Agent.Start(fun inbox ->
  5.      async { let strings = Dictionary()
  6.              while true do
  7.                let! msg = inbox.Receive()
  8.                if strings.ContainsKey msg then
  9.                    strings.[msg] <- strings.[msg] + 1
  10.                else
  11.                    strings.[msg] <- 0
  12.                printfn "message '%s' now seen '%d' times" msg strings.[msg] } )

狀態(tài)隔離是F#的基本特性,它并不是代理所獨(dú)有的。例如,下面的代碼對(duì)StreamReader和ResizeArray(這是F#中對(duì)System.Collections.Generics.List的別稱(chēng))的隔離訪(fǎng)問(wèn)。請(qǐng)注意這段代碼和.NET類(lèi)庫(kù)中的System.IO.File.ReadAllLines方法功能相同:

 
 
 
  1. let readAllLines (file:string) =
  2.     use reader = new System.IO.StreamReader(file)
  3.     let lines = ResizeArray<_>()
  4.     while not reader.EndOfStream do
  5.         lines.Add (reader.ReadLine())
  6.     lines.ToArray()

在這里,reader和ResizeArray對(duì)象都無(wú)法在函數(shù)外部使用。在代理或其他持續(xù)計(jì)算的情況里,隔離性是至關(guān)重要的──狀態(tài)在這里永遠(yuǎn)獨(dú)立于程序運(yùn)行中的其他部分。

說(shuō)到底,隔離性是個(gè)動(dòng)態(tài)的屬性,它經(jīng)常受到文法的約束。例如,考慮這樣一個(gè)延遲的,隨需加載的讀取器,它會(huì)讀取文件中的所有行:

 
 
 
  1. let readAllLines (file:string) =
  2.     seq { use reader = new System.IO.StreamReader(file)
  3.           while not reader.EndOfStream do
  4.               yield reader.ReadLine() }

隔離狀態(tài)經(jīng)常包含可變的值,包括F#中的引用單元。例如,下面的代碼在一個(gè)引用單元中不斷累計(jì)接受到的消息個(gè)數(shù):

 
 
 
  1. let agent =
  2.    Agent.Start(fun inbox ->
  3.      async { let count = ref 0
  4.              while true do
  5.                let! msg = inbox.Receive()
  6.                incr count
  7.                printfn "now seen a total of '%d' messages" !count } )

再次強(qiáng)調(diào),這里可變的狀態(tài)被隔離了,確保了對(duì)它單線(xiàn)程的安全訪(fǎng)問(wèn)。

在代理中使用循環(huán)和隔離狀態(tài)(函數(shù)式)

F#程序員了解兩種實(shí)現(xiàn)循環(huán)的方法:使用“命令式”的while/for以及可變的累加器(ref或mutable),或是“函數(shù)式”風(fēng)格的調(diào)用,將累加狀態(tài)作為參數(shù)傳遞給一個(gè)或多個(gè)遞歸函數(shù)。例如,計(jì)算文件行數(shù)的程序可以使用命令式的方式來(lái)寫(xiě):

 
 
 
  1. let countLines (file:string) =
  2.     use reader = new System.IO.StreamReader(file)
  3.     let count = ref 0
  4.     while not reader.EndOfStream do
  5.         reader.ReadLine() |> ignore
  6.         incr count
  7.     !count或是遞歸式的:
  8. let countLines (file:string) =
  9.     use reader = new System.IO.StreamReader(file)
  10.     let rec loop n =
  11.         if reader.EndOfStream then n
  12.         else
  13.             reader.ReadLine() |> ignore
  14.             loop (n+1)
  15.     loop 0

在使用時(shí),兩種方式都是可行的:函數(shù)式的做法相對(duì)更加高級(jí)一些,但是大大減少了代碼中顯式的狀態(tài)修改次數(shù),且更為通用。兩種寫(xiě)法對(duì)于F#程序員來(lái)說(shuō),一般都可以理解,他們還可以將“while”循環(huán)轉(zhuǎn)化為等價(jià)的“l(fā)et rec”函數(shù)(這是個(gè)不錯(cuò)的面試問(wèn)題?。?/p>

有趣的是,在編寫(xiě)異步循環(huán)時(shí)的規(guī)則也一樣:您可以使用命令式的“while”或函數(shù)式的“l(fā)et rec”中的任意一種來(lái)定義循環(huán)。例如,這里有一個(gè)利用遞歸的異步函數(shù)統(tǒng)計(jì)消息數(shù)量的做法:

 
 
 
  1. let agent =
  2.    Agent.Start(fun inbox ->
  3.      let rec loop n = async {
  4.          let! msg = inbox.Receive()
  5.          printfn "now seen a total of %d messages" (n+1)
  6.          return! loop (n+1)
  7.      }
  8.      loop 0 )

這樣我們便可以獲得這樣的輸出:

now seen a total of 0 messages
now seen a total of 1 messages
....
now seen a total of 10000 messages

再提一次,定義代理對(duì)象的兩種常見(jiàn)模式為命令式的:

 
 
 
  1. let agent =
  2.    Agent.Start(fun inbox ->
  3.      async {
  4.          // isolated imperative state goes here
  5.          ...
  6.          while  do
  7.              // read messages and respond
  8.              ...
  9.      })

及函數(shù)式的:

 
 
 
  1. let agent = 
  2.     Agent.Start(fun inbox ->
  3.       let rec loop arg1 arg2 = async { 
  4.           // receive and process messages here
  5.           ...
  6.           return! loop newArg1 newArg2
  7.        }
  8.       loop initialArg1 initialArg2)

再次強(qiáng)調(diào),兩種方法在F#都是合理的──使用遞歸的異步函數(shù)可能是更高級(jí)的方法,但更為函數(shù)式且更為通用。

鏈接:http://www.cnblogs.com/JeffreyZhao/archive/2010/03/15/async-and-parallel-design-patterns-in-fsharp-3-agents.html

【F#教程回顧】

  1. F#簡(jiǎn)明教程一:F#與函數(shù)式編程概述
  2. F#簡(jiǎn)明教程二:F#類(lèi)型系統(tǒng)和類(lèi)型推斷機(jī)制
  3. F#簡(jiǎn)明教程三:F#語(yǔ)法精要
  4. 詳解F#對(duì)象序列化為XML的實(shí)現(xiàn)方法
  5. F#運(yùn)算符定義規(guī)則總結(jié)

分享標(biāo)題:詳解F#異步及并行模式中的輕量級(jí)代理
轉(zhuǎn)載來(lái)源:http://www.5511xx.com/article/cceohgs.html