Parallel processing 与throttle并行的异步函数调用
我已经根据建议进行了尝试,但仍然有打嗝的问题,有人可以根据尝试提供帮助吗?我的方法签名在返回元组时是不同的,我需要将结果返回给调用者(不仅仅是执行) 这一行我有错误Parallel processing 与throttle并行的异步函数调用,parallel-processing,f#,queue,message-queue,throttling,Parallel Processing,F#,Queue,Message Queue,Throttling,我已经根据建议进行了尝试,但仍然有打嗝的问题,有人可以根据尝试提供帮助吗?我的方法签名在返回元组时是不同的,我需要将结果返回给调用者(不仅仅是执行) 这一行我有错误do!工作 错误:表达式应具有类型结果,但此处具有类型“unit” 类型错误={ 代码:int 消息:string } ///代理使用的消息类型-包含排队 ///工程项目的验收和完工通知 键入内部节流消息= |完成了结果分析 |异步排队 ///表示在中同时运行操作的代理。号码是什么时候 ///超过“限制”的并发操作数,它们将排队并稍后
do!工作
错误:表达式应具有类型结果,但此处具有类型“unit”
类型错误={
代码:int
消息:string
}
///代理使用的消息类型-包含排队
///工程项目的验收和完工通知
键入内部节流消息=
|完成了结果分析
|异步排队
///表示在中同时运行操作的代理。号码是什么时候
///超过“限制”的并发操作数,它们将排队并稍后处理
设节流剂极限=
MailboxProcessor.Start(有趣的收件箱->
异步的{
//代理主体未并行执行,
//因此,我们可以安全地使用可变队列和计数器
让queue=System.Collections.Generic.queue()
让运行=参考0
尽管如此
//将新工作项排队或减少计数器
//有多少任务在后台运行
let!msg=inbox.Receive()
配味精
|已完成r->decr运行
|排队w->queue.Enqueue(w)
//如果我们有少于极限&还有一些工作要做
//做,然后在后台开始工作!
运行时.Value0 do
let work=queue.Dequeue()
递增运行
do!//工作完成后,发送“已完成”
//返回代理以释放插槽
异步的{
干!干
收件箱.邮件(已完成)
}
|>Async.StartChild
|>异步。忽略
})
让requestAsync(url:string):异步=
异步的{
Console.WriteLine(“模拟请求”+url)
尝试
do!Async.Sleep(1000)
返回Ok(url+“:body…”)
使用:?WebException作为e->
返回错误{code=500;message=“内部服务器错误”;}
}
让URL=[|
"http://www.example.com/1";
"http://www.example.com/2";
"http://www.example.com/3";
"http://www.example.com/4";
"http://www.example.com/5";
"http://www.example.com/6";
"http://www.example.com/7";
"http://www.example.com/8";
"http://www.example.com/9";
|]
设w=节流剂3
对于url中的url,请执行以下操作:
请求异步url
|>排队
|>w.邮政
我认为问题在于您试图修改代理,使工作项不是异步的,即运行和完成时不返回结果的操作,而是实际返回内容的操作。你可以这样做,但你必须决定你想对结果做什么
在这种情况下,我认为让代理保持原样更容易,而是在最后处理结果的收集。例如,如果要在集合中收集它们,可以编写:
let results = System.Collections.Concurrent.ConcurrentBag<_>()
let w = throttlingAgent 3
for url in urls do
async {
let! res = requestAsync url
results.Add res } |> Enqueue |> w.Post
let results=System.Collections.Concurrent.ConcurrentBag()
设w=节流剂3
对于url中的url,请执行以下操作:
异步{
let!res=requestAsync url
结果.添加res}|>Enqueue}>w.Post
为完整起见,这使用了以下类型和代理的定义:
type Error = {
code : int
message : string
}
/// Message type used by the agent - contains queueing
/// of work items and notification of completion
type ThrottlingAgentMessage =
| Completed
| Enqueue of Async<unit>
/// Represents an agent that runs operations in concurrently. When the number
/// of concurrent operations exceeds 'limit', they are queued and processed later
let throttlingAgent limit =
MailboxProcessor.Start(fun inbox ->
async {
// The agent body is not executing in parallel,
// so we can safely use mutable queue & counter
let queue = System.Collections.Generic.Queue<Async<unit>>()
let running = ref 0
while true do
// Enqueue new work items or decrement the counter
// of how many tasks are running in the background
let! msg = inbox.Receive()
match msg with
| Completed -> decr running
| Enqueue w -> queue.Enqueue(w)
// If we have less than limit & there is some work to
// do, then start the work in the background!
while running.Value < limit && queue.Count > 0 do
let work = queue.Dequeue()
incr running
do! // When the work completes, send 'Completed'
// back to the agent to free a slot
async {
do! work
inbox.Post(Completed)
}
|> Async.StartChild
|> Async.Ignore
})
let requestAsync (url: string) : Async<Result<string, Error>> =
async {
Console.WriteLine ("Simulating request " + url)
try
do! Async.Sleep(1000)
return Ok (url + ":body...")
with :? WebException as e ->
return Error {code = 500; message = "Internal Server Error";}
}
类型错误={
代码:int
消息:string
}
///代理使用的消息类型-包含排队
///工程项目的验收和完工通知
键入ThrottlingAgentMessage=
|完成
|异步排队
///表示在中同时运行操作的代理。号码是什么时候
///超过“限制”的并发操作数,它们将排队并稍后处理
设节流剂极限=
MailboxProcessor.Start(有趣的收件箱->
异步的{
//代理主体未并行执行,
//因此,我们可以安全地使用可变队列和计数器
让queue=System.Collections.Generic.queue()
让运行=参考0
尽管如此
//将新工作项排队或减少计数器
//有多少任务在后台运行
let!msg=inbox.Receive()
配味精
|已完成->decr正在运行
|排队w->queue.Enqueue(w)
//如果我们有少于极限&还有一些工作要做
//做,然后在后台开始工作!
运行时.Value0 do
let work=queue.Dequeue()
递增运行
do!//工作完成后,发送“已完成”
//返回代理以释放插槽
异步的{
干!干
收件箱.邮件(已完成)
}
|>Async.StartChild
|>异步。忽略
})
让requestAsync(url:string):异步=
异步的{
Console.WriteLine(“模拟请求”+url)
尝试
do!Async.Sleep(1000)
返回Ok(url+“:body…”)
使用:?WebException作为e->
返回错误{code=500;message=“内部服务器错误”;}
}
Hi Taylor的可能副本,我将在此基础上尝试并发布一些编辑以供可能的审阅,请修复我的特定签名有问题Async
,而解决方案有不同的签名。您可以审阅我的签名吗attempt@TaylorWood我认为这不是复制品。OP试图修改前面的答案,做一些不同的事情。谢谢Tomas。问题,这是一个长期运行的过程吗<代码>为true时执行
。我要测试和研究这个。如果它是一个持续长时间运行的过程,那么我需要进一步定制它,以便在
type Error = {
code : int
message : string
}
/// Message type used by the agent - contains queueing
/// of work items and notification of completion
type ThrottlingAgentMessage =
| Completed
| Enqueue of Async<unit>
/// Represents an agent that runs operations in concurrently. When the number
/// of concurrent operations exceeds 'limit', they are queued and processed later
let throttlingAgent limit =
MailboxProcessor.Start(fun inbox ->
async {
// The agent body is not executing in parallel,
// so we can safely use mutable queue & counter
let queue = System.Collections.Generic.Queue<Async<unit>>()
let running = ref 0
while true do
// Enqueue new work items or decrement the counter
// of how many tasks are running in the background
let! msg = inbox.Receive()
match msg with
| Completed -> decr running
| Enqueue w -> queue.Enqueue(w)
// If we have less than limit & there is some work to
// do, then start the work in the background!
while running.Value < limit && queue.Count > 0 do
let work = queue.Dequeue()
incr running
do! // When the work completes, send 'Completed'
// back to the agent to free a slot
async {
do! work
inbox.Post(Completed)
}
|> Async.StartChild
|> Async.Ignore
})
let requestAsync (url: string) : Async<Result<string, Error>> =
async {
Console.WriteLine ("Simulating request " + url)
try
do! Async.Sleep(1000)
return Ok (url + ":body...")
with :? WebException as e ->
return Error {code = 500; message = "Internal Server Error";}
}