Why Async.Sequential doesn't work as expected (but works in FSI)?

Viewed 135
open System
open System.Net

let fetchUrlAsync url = 
    async {
        Console.WriteLine(sprintf "Fetch <%s>" url)
        let req = WebRequest.Create(Uri(url)) 
        use! resp = req.AsyncGetResponse()   
        use stream = resp.GetResponseStream() 
        use reader = new IO.StreamReader(stream) 
        let html = reader.ReadToEnd() 
        Console.WriteLine(sprintf "finished downloading %s. Length = %i" url html.Length)
    }

[<EntryPoint>]
let main argv =
    ["http://bing.com"; "http://ya.ru"; "http://google.com"]
    |> List.map fetchUrlAsync
    |> Async.Sequential
    |> Async.Ignore
    |> Async.RunSynchronously


The output:

Fetch <http://bing.com>
Fetch <http://ya.ru>
Fetch <http://google.com>
finished downloading http://google.com. Length = 50592
finished downloading http://ya.ru. Length = 20541
finished downloading http://bing.com. Length = 81386

I don't expect such an output (but perhaps I'm wrong with my expectations). But if I run the same code in F# interactive the output is (as I expected):

Fetch <http://bing.com>
finished downloading http://bing.com. Length = 81386
Fetch <http://ya.ru>
finished downloading http://ya.ru. Length = 20544
Fetch <http://google.com>
finished downloading http://google.com. Length = 50561

Why the code behaves differently when running from Rider (console application) and from F# Interactive? If the first output is correct, then what is the difference between Async.Sequential and Async.Parallel? If the first output is incorrect, then how to fix that?

1 Answers

Currently, Async.Sequential is just implemented as:

static member Sequential computations = 
    Async.Parallel(computations, maxDegreeOfParallelism=1)

Though the RFC allows this, this is expected to, well, run sequentially. It's been discovered to be a bug. And it has been fixed by #7596.

The fix has now only shipped on VS. But it's not in mainline FSharp.Core nuget feed yet.

The only way to get the fix currently is through VS2019 16.4 FSI.

That's why you're seeing that it works correctly in FSI, but not in your compiled application.

Solution

Watch #7956, and wait for it to ship.

Related