http 下载到磁盘 fsharp.data.dll 和异步工作流停顿

http download to disk with fsharp.data.dll and async workflows stalls

以下 .fsx 文件应该下载并保存到磁盘二进制 table 基础文件,这些文件作为链接发布在互联网上的 html 页面中,使用 Fsharp.Data.dll

发生的事情是,整个事情在完成一段时间后停滞不前,甚至没有抛出异常或类似的东西。

我很确定,我在我的异步工作流程中处理 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,因为这似乎是正确的方法。

News 有趣的是:如果我中断停滞的脚本,然后将其再次#load 到 fsi.exe 的同一个实例中,它会立即停滞。我开始认为这是我使用的库中的错误或类似的错误。

提前致谢!

此处修改了 fetchAndSave 以异步处理从 CopyToAsync 返回的任务。在您的版本中,您正在同步等待任务。当您使用 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()

在你的脚本的最后一行启动。