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()
在你的脚本的最后一行启动。
以下 .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()
在你的脚本的最后一行启动。