我一直在努力學習過去幾天的F#,並且一直困擾着我。我的「學習項目」是我對操作感興趣的一些數據的屏幕刮板。響應流昂貴的異步讀取
在F#PowerPack中有一個調用Stream.AsyncReadToEnd。我不想僅僅爲了這個單獨的電話而使用PowerPack,所以我看看他們是如何做到的。
module Downloader =
open System
open System.IO
open System.Net
open System.Collections
type public BulkDownload(uriList : IEnumerable) =
member this.UriList with get() = uriList
member this.ParalellDownload() =
let Download (uri : Uri) = async {
let UnblockViaNewThread f = async {
do! Async.SwitchToNewThread()
let res = f()
do! Async.SwitchToThreadPool()
return res }
let request = HttpWebRequest.Create(uri)
let! response = request.AsyncGetResponse()
use responseStream = response.GetResponseStream()
use reader = new StreamReader(responseStream)
let! contents = UnblockViaNewThread (fun() -> reader.ReadToEnd())
return uri, contents.ToString().Length }
this.UriList
|> Seq.cast
|> Seq.map Download
|> Async.Parallel
|> Async.RunSynchronously
他們有那個函數UnblockViaNewThread。這真的是異步讀取響應流的唯一方法嗎?是不是創建一個新的線程真的很昂貴(我已經看到了在整個地方引發的「1mb內存」)。有一個更好的方法嗎?這是每個Async*
電話(我可以let!
)中發生的情況嗎?
編輯:我遵循托馬斯的建議,實際上想出了獨立於F#PowerTools的東西。這裏是。這確實需要錯誤處理,但它會異步請求並將url下載到字節數組。
namespace Downloader
open System
open System.IO
open System.Net
open System.Collections
type public BulkDownload(uriList : IEnumerable) =
member this.UriList with get() = uriList
member this.ParalellDownload() =
let Download (uri : Uri) = async {
let processStreamAsync (stream : Stream) = async {
let outputStream = new MemoryStream()
let buffer = Array.zeroCreate<byte> 0x1000
let completed = ref false
while not (!completed) do
let! bytesRead = stream.AsyncRead(buffer, 0, 0x1000)
if bytesRead = 0 then
completed := true
else
outputStream.Write(buffer, 0, bytesRead)
stream.Close()
return outputStream.ToArray() }
let request = HttpWebRequest.Create(uri)
let! response = request.AsyncGetResponse()
use responseStream = response.GetResponseStream()
let! contents = processStreamAsync responseStream
return uri, contents.Length }
this.UriList
|> Seq.cast
|> Seq.map Download
|> Async.Parallel
|> Async.RunSynchronously
override this.ToString() = String.Join(", ", this.UriList)
這完全回答了我的問題。感謝Tomas。 –