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

面向对象技术开发

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

F#中的异步及并行模式(3 - 上):代理

来源: www.bianceng.cn 阅读:

第1部分描述了F#作为一个并行及异步语言,是如何支持轻量级的响应操作,并给出了CPU异步并行和I/O异步并行两种模式。

第2部分描述了如何从异步计算或后台计算单元中获得结果。

模式4:您的第一个代理

我们来观察您所创建的第一个异步代理:

type Agent<'T> = MailboxProcessor<'T>

let agent =
   Agent.Start(fun inbox ->
    async { while true do
         let! msg = inbox.Receive()
         printfn "got message '%s'" msg } )

这个代理不断地异步等待消息,并将它们打印出来。在这段代码中,每个消息都是一个字符串,且agent的类型是:

agent.Post "hello!"

这便会打印出:

got message 'hello!'

也可以这样发送多条消息:

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

这样便可以打印出10000条消息。

您可以认为每个代理对象都包含一个消息队列(或管道),并在消息到达时进行响应。一个委托一般都使用异步的循环等待来消息并进行处理。如在上面的例子中,代理使用while循环进行处理。

许多读者可能已经对代理颇为熟悉了。如Erlang,它便是基于代理设计的(在那里被称为进程)。而不久之前,一个基于.NET平台的实验性的孵化型语言,Axum,也注重了基于代理编程的重要性。Axum与F#中的代理设计相互影响,而其他包含轻量级线程的语言也强调了基于代理的组合与设计。

上面的例子一开始创建了一个类型的缩写:Agent,它代表了F#类库中基于内存的代理类型“MailboxProcessor”。如果您愿意的话也可以使用这个完整的名字,不过我更喜欢简单的命名。

您的第一批10万个代理

代理对象非常轻量,这是因为它基于F#的异步编程模型。例如,您可以在一个.NET进程中创建成百上千,甚至更多个代理。例如,我们来创建10万个简单的代理对象:

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

您可以这样向每个代理对象发送消息:

for agent in agents do
   agent.Post "ping!

每第1万个代理对象会在收到消息时打印信息。这个代理集合在处理消息时非常迅速,只要几秒钟时间。代理和内存中的消息处理非常快。

很显然,代理并不与.NET线程直接对应──您不可能在单个应用程序中创建10万的线程(在32位操作系统中,即便1000个线程也已经太多了)。相反,在代理等待消息时,它实际上只是表现为一个回调函数,一些对象分配,以及代理所引用的闭包等等。在收到消息之后,代理的工作会在一个线程池(默认便是.NET线程池)中分配并执行。

尽管需要10万个代理的情况并不多见,不过2000多个代理倒是很正常的。接下来我们便会看到这样一些例子。

Tags:
相关文章列表: