F#中的异步及并行模式(3 - 下):代理的进一步使用 - 面向对象网 f# 学习 对象 - 面向对象技术开发

面向对象技术开发

会员投稿 投稿指南 站长资讯通告:
您的位置: 首页 > OOP语言 > F# > 正文

F#中的异步及并行模式(3 - 下):代理的进一步使用

来源: www.bianceng.cn 阅读:

在本系列的第3部分中,我们会来探索F#中轻量级的,交互式的代理,以及与代理有关的一些模式,包括隔离的内部状态。(译注:由于原文内容较多,译文拆成两段进行。在上半段文章中讨论了代理的基本使用方式,而下半段则讨论关于代理使用中更进一步的模式。)

消息与联合类型

很多时候我们会使用联合类型(Union Type)作为消息的类型。例如,我将要展示一个基于代理的DirectX示例,我们要在模拟引擎中使用如下的消息:

type Message =
   | PleaseTakeOneStep
   | PleaseAddOneBall of Ball

模拟引擎中的代理:

let simulationEngine =
   Agent.Start(fun inbox ->
     async { while true do
           // Wait for a message
           let! msg = inbox.Receive()

           // Process a message
           match msg with
           | PleaseTakeOneStep -> state.Transform moveBalls
           | PleaseAddOneBall ball -> state.AddObject ball })

在很多情况下使用强类型消息是个不错的做法。不过,在某些您需要和其他消息机制协作的时候,也无需担心使用如“obj”和“string”等泛化的消息类型,此时代理只需要在运行时进行类型判断或转化即可。

参数化代理及抽象代理

代理只是F#编码中的一种设计模式。这意味着您可以将F#中各种常用的技巧,如参数化,抽象或是代码片段重用与代理一起使用。例如,您可以把之前的serveQuoteStream函数参数化,指定每条股票消息传输中的间隔时间:

open System.Net.Sockets

/// serve up a stream of quotes
let serveQuoteStream (client: TcpClient, periodMilliseconds: int) = async {
   let stream = client.GetStream()
   while true do
     do! stream.AsyncWrite( "AAPL 439.2"B )
     do! Async.Sleep periodMilliseconds
}

这意味着您的股票服务器中不同的请求可以拥有不同长度的间隔。

与此类似,您可以使用函数参数,将整个代理类的功能进行抽象:

let iteratingAgent job =
   Agent.Start(fun inbox ->
    async { while true do
         let! msg = inbox.Receive()
         do! job msg })

let foldingAgent job initialState =
   Agent.Start(fun inbox ->
    let rec loop state = async {
      let! msg = inbox.Receive()
      let! state = job state msg
      return! loop state
     }
    loop initialState)

您可以这样使用第一个函数:

let agent1 = iteratingAgent (fun msg -> async { do printfn "got message '%s'" msg })

及第二个:

let agent2 =
   foldingAgent (fun state msg ->
     async { if state % 1000 = 0 then printfn "count = '%d'" msg;
         return state + 1 }) 0

Tags:
相关文章列表: