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

时间:2015-07-07 09:41:25

标签: f# f#-data

以下.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的同一个实例中,它就会立即停止。我开始认为这是我使用的库中的一个错误或类似的东西。

先谢谢!

1 个答案:

答案 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()
在脚本的最后一行

启动动作。