Asparallel(). Forall vs async await

Asked

Viewed 384 times

3

When to use AsParallel().ForAll, and when to use async await?

I am providing an example with a download and file manipulation routine.

The AsParallel().ForAll has better performance in the download operation in parallel.
The async await has better performance in parallel file handling operation.

If anyone can explain the difference and the best use scenario of each, I would appreciate.

Code (also available in .NET Fiddle):

using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace Parallel
{
    public enum Actions
    {
        TestParallelDownload,
        TestParallelSaveFile,
        TestAsyncDownload,
        TestAsyncSaveFile
    }

    public class Program
    {
        public static async Task Main(string[] args)
        {
            try
            {
                var stopWatch = Stopwatch.StartNew();
                var itemAmount = 5;

                await Test(Actions.TestParallelDownload, itemAmount);
                await Test(Actions.TestParallelSaveFile, itemAmount);

                await Test(Actions.TestAsyncDownload, itemAmount);
                await Test(Actions.TestAsyncSaveFile, itemAmount);

                stopWatch.Stop();
                Console.WriteLine("Finish {0}", stopWatch.Elapsed);
                Console.ReadLine();
            }
            catch (Exception ex)
            {
                Console.WriteLine("Err", ex.Message);
                Console.ReadLine();
            }
        }

        public static async Task Test(Actions action, int itemAmount)
        {
            string[] items = Enumerable.Range(0, itemAmount).Select(i => Guid.NewGuid().ToString()).ToArray();
            var stopWatch = Stopwatch.StartNew();

            switch (action)
            {
                case Actions.TestParallelDownload:
                    items.AsParallel().ForAll(item => DownloadAsync(item));
                    break;
                case Actions.TestParallelSaveFile:
                    items.AsParallel().ForAll(item => SaveAsync(item));
                    break;
                case Actions.TestAsyncDownload:
                    foreach (var item in items)
                        await DownloadAsync(item);
                    break;
                case Actions.TestAsyncSaveFile:
                    foreach (var item in items)
                        await SaveAsync(item);
                    break;
            }

            stopWatch.Stop();

            Console.WriteLine($"{action.ToString()} Call: Time: {stopWatch.Elapsed}");
        }

        public static async Task SaveAsync(string textToWrite)
        {
            string filePath = @"C:\temp\file2.txt";
            byte[] encodedText = Encoding.Unicode.GetBytes(textToWrite);

            using (var sourceStream = new FileStream(filePath,
                FileMode.Append, FileAccess.Write, FileShare.None,
                bufferSize: 4096, useAsync: true))
            {
                await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
            };
        }

        public static async Task DownloadAsync(string name)
        {
            var uri = new Uri("https://images.sftcdn.net/images/t_app-logo-l,f_auto,dpr_auto/p/ce2ece60-9b32-11e6-95ab-00163ed833e7/2183169552/the-test-fun-for-friends-logo.png");
            using (var client = new WebClient())
            {
                await client.DownloadFileTaskAsync(uri, $"{name}.png");
            }
        }
    }
}

Unfortunately, because it contains file manipulation, the code does not run correctly on the cloud, it is necessary to create a Console . NET Core project to run it.

1 answer

4


As commented by João Martins, Asparallel is multi-threading - i.e., you are running tasks in parallel using multiple threads - and async/await is asynchronous - i.e., the task can be stopped by releasing the thread present, and will continue later, possibly in another thread.

So in the case of your actions TestParallel*, you will potentially be using more than one thread. But see that there is a bug in them: because there is no await (or in the case of Linq/Plinq a .Result or .Wait() in methods that return Task/Task<T>) may happen the program ends and the downnload or save of the files does not complete...

An alternative that would solve this and give the sense of parallelism would be to change to something like:

await Task.WhenAll(items.Select(item => DownloadAsync(item));

In the case of actions TestAsync*, they will run serially in a single thread, which will be interrupted at the start of I/O operations and will continue at the end of each.

Browser other questions tagged

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