gpt4 book ai didi

multithreading - F# MailboxProcessor 限制并行度

转载 作者:行者123 更新时间:2023-12-04 22:55:14 24 4
gpt4 key购买 nike

我是 F# 的新手,并尝试使用 MailboxProcessor 来确保状态更改是单独完成的。

简而言之,我将操作(描述状态更改的不可变对象(immutable对象))发布到 MailboxProcessor,在递归函数中我读取消息并生成新状态(即在下面的示例中将项目添加到集合中)并将该状态发送到下一次递归。

open System

type AppliationState =
{
Store : string list
}
static member Default =
{
Store = List.empty
}
member this.HandleAction (action:obj) =
match action with
| :? string as a -> { this with Store = a :: this.Store }
| _ -> this

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

[<AbstractClass; Sealed>]
type AppHolder private () =
static member private Processor = Agent.Start(fun inbox ->
let rec loop (s : AppliationState) =
async {
let! action = inbox.Receive()
let s' = s.HandleAction action
Console.WriteLine("{s: " + s.Store.Length.ToString() + " s': " + s'.Store.Length.ToString())
return! loop s'
}
loop AppliationState.Default)

static member HandleAction (action:obj) =
AppHolder.Processor.Post action

[<EntryPoint>]
let main argv =
AppHolder.HandleAction "a"
AppHolder.HandleAction "b"
AppHolder.HandleAction "c"
AppHolder.HandleAction "d"

Console.ReadLine()
0 // return an integer exit code

预期输出为:
s: 0 s': 1
s: 1 s': 2
s: 2 s': 3
s: 3 s': 4

我得到的是:
s: 0 s': 1
s: 0 s': 1
s: 0 s': 1
s: 0 s': 1

阅读 MailboxProcessor 的文档并对其进行谷歌搜索,我的结论是它是一个消息队列,由“单线程”处理,而不是看起来它们都是并行处理的。

我在这里完全不在场吗?

最佳答案

问题是你认为 AppHolder.Processor每次都是同一个对象,但实际上每次都是不同的 MailboxProcessor。我将您的 AppHolder 代码更改为以下内容:

[<AbstractClass; Sealed>]
type AppHolder private () =
static member private Processor =
printfn "Starting..."
Agent.Start(fun inbox ->
let rec loop (s : AppliationState) =
async {
let! action = inbox.Receive()
let s' = s.HandleAction action
printfn "{s: %A s': %A}" s s'
return! loop s'
}
loop AppliationState.Default)

static member HandleAction (action:obj) =
AppHolder.Processor.Post action

我所做的唯一更改是简化 Console.WriteLine 调用以使用 printfn%A获取更多调试细节,并添加单个 printfn "Starting..."将在 MailboxProcessor 构建和启动之前立即执行的调用。我得到的输出是:
Starting...
Starting...
Starting...
Starting...
{s: {Store = [];} s': {Store = ["b"];}}
{s: {Store = [];} s': {Store = ["d"];}}
{s: {Store = [];} s': {Store = ["c"];}}
{s: {Store = [];} s': {Store = ["a"];}}

注意 printfn "Starting..."行已执行四次。

这吸引了很多 F# 新手: member关键字定义属性,而不是字段。每次评估属性时,都会重新评估该属性的主体。所以每次访问 AppHolder.Processor ,你得到一个新的邮箱处理器。见 https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/members/properties更多细节。

您可能想要的是以下内容:
[<AbstractClass; Sealed>]
type AppHolder private () =
static let processor =
printfn "Starting..."
Agent.Start(fun inbox ->
// ...
)

static member HandleAction (action:obj) =
processor.Post action

关于multithreading - F# MailboxProcessor 限制并行度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50135825/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com