澄清问题:
我有以下脚本访问Web和本地资源。我想将Web连接限制为N(网站很慢),本地资源访问(executeLocalNetworkProcess
)不应阻止其他Web请求。 (因此它将始终运行N个Web请求)。
某些类别的项目很少,而其他类别则很多。应该为所有类别的所有项目运行并行执行以利用Web连接。
let categories = getCategories() // get a seq of category from web service
for c in categories do
getItemsByCategory c // returns a seq of item from web
|> Seq.iter (fun (item, _) -> // Want to process N items in parallel
getMoreDataFromWeb item // from web
executeLocalNetworkProcess item // local disk/network access; may take a while
downloadBigFile item // from web
)
在F#中实现它的最佳方法是什么?
答案 0 :(得分:1)
我之前做过类似的事情,将序列分成大小为n
的批次并并行处理批次。
我们可以使用此SO答案中的代码创建序列批次:https://stackoverflow.com/a/7518857/2461791
从那里我们只需要并行遍历每个批次中的项目。我喜欢把它放在Array.Parallel
模块中。
module Array =
module Parallel =
let batchIter size action array =
let batchesOf n =
Seq.mapi (fun i v -> i / n, v) >>
Seq.groupBy fst >>
Seq.map snd >>
Seq.map (Seq.map snd)
for batch in array |> batchesOf size do
batch
|> Seq.toArray
|> Array.Parallel.iter action
以下代码将100个项目的列表拆分为8个批次,并且并行打印每个批次的项目。
[1..100]
|> Array.Parallel.batchIter 8 (printfn "%d")
要将此应用于您的代码,您会看到类似这样的内容:
let categories = getCategories()
for c in categories do
match c with | (category, description, _) -> printfn "%s" category
getItemsByCategory c
|> Array.Parallel.batchIter 8 (fun (item, description, _) ->
process item
)
然而,这种方法将在开始下一批次之前等待整批处理完成处理。
答案 1 :(得分:1)
您可能希望在自己的基础库中包含F#PowerPack的PSeq模块源代码。然后,您只需调用PSeq.iter:
for category, description, _ as c in getCategories() do
printfn "%s" category
getItemsByCategory c
|> PSeq.iter(fun (item, description, _) -> process item)