Download with Httpwebclient only works outside of Parallel.Foreach

Asked

Viewed 49 times

1

I am developing a class for downloading C files#: Filedownloader. The problem is occurring in using it. I am trying to make simultaneous downloads, it is working normal when it is running outside the Parallel but when it spins inside it using (var response = await request.GetResponseAsync()) // line 205 da classe DownloadFile is waiting forever ignoring the TimeOut and does not download.

    private async void DoDownload(string[] segments)
    {                   
        //Whether to stop downloading
        stopdownload = false;
        cts = new CancellationTokenSource();

        //Multi-threaded setup
        ParallelOptions parallelOptions = new ParallelOptions
        {
            MaxDegreeOfParallelism = 2,
            CancellationToken = cts.Token
        };

        //Start Downloading
        OnDownloadStart?.Invoke(this, EventArgs.Empty);
        DownloadStatus = DownloadStatus.Downloading;


        var downloader1 = new Downloader.DownloadFile()
        {
            Url = @"https://github.com/BtbN/FFmpeg-Builds/releases/download/autobuild-2021-03-13-12-31/ffmpeg-n4.3.2-160-gfbb9368226-win64-gpl-4.3.zip",
            FilePath = Path.Combine(OutFolder.FullName, $"part_10.zip")
        };
        await downloader1.StartAsync();


        try
        {
            Parallel.ForEach(segments, parallelOptions,  async (info, loopstate, index) =>
                {
                    if (stopdownload)
                        loopstate.Stop();

                    var downloader2 = new Downloader.DownloadFile()
                    {
                        Url = @"https://github.com/BtbN/FFmpeg-Builds/releases/download/autobuild-2021-03-13-12-31/ffmpeg-n4.3.2-160-gfbb9368226-win64-gpl-4.3.zip",
                        FilePath = Path.Combine(OutFolder.FullName, $"part_{index}.zip")
                    };
                    await downloader2.StartAsync();

                });
        }
        catch (OperationCanceledException)
        {
            ;
        }
    }

The downloader1 drops normally while the downloader2 no. I fixed the url to one that I was sure was working. But why is this happening?

1 answer

1

The objective of Parallel.ForEach is to parallelize Tasks but not with async/await, where you hope to return a Task and hope that it is completed.

The Parallel.ForEach shall work well with another synchronous method of WebClient.

To make async, has a much simpler approach that is to use own System.Linq to create Tasks and await their outcome, something like this:

// Para cada "segment" crio uma Task de download
var downloadsTasks = segments.Select(segment =>
{
    return new Downloader.DownloadFile
    {
          Url = segment,
          FilePath = Path.Combine(OutFolder.FullName, $"part_{segment}.zip")
    }.StartAsync();    
});

// Aguardo todos os downloads terminarem.
var downloads = await Task.WhenAll(downloadsTasks);

Assuming "Segments" has the download links or can mount the download name within the .Select. This ensures you will return Tasks and will do the await next.

  • Thanks for the reply, I removed the async of the code and again made the downloads normally only that generated another problem. Both in its implementation and in the withdrawal of the async both ways make as many downloads as possible, but I need to have control over how many files I’m downloading at a time. For example some cases I will not be able to pass 2 and others 4 simultaneous downloads.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.