以下.fsx文件应该下载并保存到磁盘二进制表基本文件,这些文件使用Fsharp.Data.dll
在互联网上的html页面中作为链接发布。
会发生什么事情,整个事情在一段时间之后就会停止,并且在完成之前就会停止,甚至不会抛出异常或类似事件。
我很确定,我在异步工作流程中错误处理CopyToAsync()
内容。因为这应该是在我小睡的时候运行,如果有人能告诉我应该如何正确地完成它会很好。 (更笼统地说 - 如何处理异步工作流中的System.Threading.Task东西?)
#r @"E:\R\playground\DataTypeProviderStuff\packages\FSharp.Data.2.2.3\lib\net40\FSharp.Data.dll"
open FSharp.Data
open Microsoft.FSharp.Control.CommonExtensions
let document = HtmlDocument.Load("http://www.olympuschess.com/egtb/gaviota/")
let links =
document.Descendants ["a"] |> Seq.choose (fun x -> x.TryGetAttribute("href") |> Option.map (fun a -> a.Value()))
|> Seq.filter (fun v -> v.EndsWith(".cp4"))
|> List.ofSeq
let targetFolder = @"E:\temp\tablebases\"
let downloadUrls =
links |> List.map (fun name -> "http://www.olympuschess.com/egtb/gaviota/" + name, targetFolder + name )
let awaitTask = Async.AwaitIAsyncResult >> Async.Ignore
let fetchAndSave (s,t) =
async {
printfn "Starting with %s..." s
let! result = Http.AsyncRequestStream(s)
use fileStream = new System.IO.FileStream(t,System.IO.FileMode.Create)
do! awaitTask (result.ResponseStream.CopyToAsync(fileStream))
printfn "Done with %s." s
}
let makeBatches n jobs =
let rec collect i jl acc =
match i,jl with
| 0, _ -> acc,jl
| _, [] -> acc,jl
| _, x::xs -> collect (i-1) (xs) (acc @ [x])
let rec loop remaining acc =
match remaining with
| [] -> acc
| x::xs ->
let r,rest = collect n remaining []
loop rest (acc @ [r])
loop jobs []
let download () =
downloadUrls
|> List.map fetchAndSave
|> makeBatches 2
|> List.iter (fun l -> l |> Async.Parallel |> Async.RunSynchronously |> ignore )
|> ignore
download()
注意更新了代码,因此它一次创建2个下载批次,只有第一个批次有效。还从第一个答案添加了awaitTask,因为这似乎是正确的方法。
新闻什么也很有趣:如果我中断了停滞的脚本,然后再将#load加载到fsi.exe的同一个实例中,它就会立即停止。我开始认为这是我使用的库中的一个错误或类似的东西。
先谢谢!
答案 0 :(得分:2)
此处fetchAndSave已被修改为异步处理从CopyToAsync返回的Task。在您的版本中,您正在等待任务同步。当您使用Async.RunSynchronously运行整个工作流程时,您的脚本似乎会锁定。但是文件会在后台按预期下载。
let awaitTask = Async.AwaitIAsyncResult >> Async.Ignore
let fetchAndSave (s,t) = async {
let! result = Http.AsyncRequestStream(s)
use fileStream = new System.IO.FileStream(t,System.IO.FileMode.Create)
do! awaitTask (result.ResponseStream.CopyToAsync(fileStream))
}
当然你还需要打电话
do download()
在脚本的最后一行启动动作。