open System
open System.IO
open System.Net
open System.Threading

// ------------------------------------------------------------------
// Read a stream into the memory and then return it as a string
// ------------------------------------------------------------------

let readToEnd (stream:Stream) = async {
  // Allocate 1kb buffer for downloading dat
  let buffer = Array.zeroCreate 1024
  use output = new MemoryStream()
  let finished = ref false
  
  while not finished.Value do
    // Download one (at most) 1kb chunk and copy it
    let! count = stream.AsyncRead(buffer, 0, 1024)
    do! output.AsyncWrite(buffer, 0, count)
    finished := count <= 0

  // Read all data into a string
  output.Seek(0L, SeekOrigin.Begin) |> ignore
  use sr = new StreamReader(output)
  return sr.ReadToEnd() }


// ------------------------------------------------------------------
// Download a web page using HttpWebRequest
// ------------------------------------------------------------------

/// Downlaod content of a web site using 'readToEnd'
let download url = async {
  let request = HttpWebRequest.Create(Uri(url))
  use! response = request.AsyncGetResponse()
  use stream = response.GetResponseStream()
  let! res = readToEnd stream 
  return res }

// Create a list of sites to download 

let sites = 
  [ "http://webstep.no"
    "http://microsoft.com"
    "http://bing.com"
    "http://google.com" ]

// Fork-join parallelism (download all)
let downloads = sites |> List.map download
let alldata = Async.Parallel downloads

// Run synchronously & block the thread
let res = Async.RunSynchronously(alldata)

// Create a background task that will eventually
// print (or do some other side-effect)
let work = async { 
  let! res = alldata 
  for it in res do
    printfn "%d" it.Length }

Async.Start(work)