저는 지난 몇 달 동안 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 기능을 가지고 있습니다. 실제로 비동기 적으로 응답 스트림을 읽는 유일한 방법입니까? 정말 새로운 스레드를 만드는 것은 비싸지 않습니다. ("1 메가 바이트의 메모리"가 모든 곳에 던져진 것을 보았습니다.) 이 작업을 수행하는 더 좋은 방법이 있습니까? 이것은 Async*
전화 (실제로는 let!
일 수 있음)에서 실제로 발생하는 것입니까?
편집 : 나는 Tomas의 제안을 따르고 실제로 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)
내 질문에 완전히 대답합니다. 고마워요 토마스. –