1

Parallel.ForEachAsync in .NET 6

 2 years ago
source link: https://www.hanselman.com/blog/parallelforeachasync-in-net-6
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Parallel.ForEachAsync in .NET 6

Sponsored By

Great tweet from Oleg Kyrylchuk (follow him!) showing how cool Parallel.ForEachAsync is in .NET 6. It's new! Let's look at this clean bit of code in .NET 6 that calls the public GitHub API and retrieves n number of names and bios, given a list of GitHub users:

using System.Net.Http.Headers;
using System.Net.Http.Json;
var userHandlers = new []
{
"users/okyrylchuk",
"users/shanselman",
"users/jaredpar",
"users/davidfowl"
};
using HttpClient client = new()
{
BaseAddress = new Uri("https://api.github.com"),
};
client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("DotNet", "6"));
ParallelOptions parallelOptions = new()
{
MaxDegreeOfParallelism = 3
};
await Parallel.ForEachAsync(userHandlers, parallelOptions, async (uri, token) =>
{
var user = await client.GetFromJsonAsync<GitHubUser>(uri, token);
Console.WriteLine($"Name: {user.Name}\nBio: {user.Bio}\n");
});
public class GitHubUser
{
public string Name { get; set; }
public string  Bio { get; set; }
}

Let's note a few things in this sample Oleg shared. First, there's no Main() as that's not required (but you can have it if you want).

We also see just two usings, bringing other namespaces into scope. Here's what it would look like with explicit namespaces:

using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Threading.Tasks;

We've got an array of users to look up in userHandlers. We prep an HttpClient and setup some ParallelOptions, giving our future ForEach the OK to "fan out" to up to three degrees of parallelism - that's the max number of concurrent tasks we will enable in one call. If it's -1 there is no limit to the number of concurrently running operations.

The really good stuff is here. Tight and clean:

await Parallel.ForEachAsync(userHandlers, parallelOptions, async (uri, token) =>
{
var user = await client.GetFromJsonAsync<GitHubUser>(uri, token);
Console.WriteLine($"Name: {user.Name}\nBio: {user.Bio}");
});

"Take this array and naively fan out into parallel tasks and make a bunch of HTTP calls. You'll be getting JSON back that is shaped like the GitHubUser."

We could make it even syntactically shorter if we used a record vs a class with this syntax:

public record GitHubUser (string Name, string Bio);

This makes "naïve" parallelism really easy. By naïve we mean "without inter-dependencies." If you want to do something and you need to "fan out" this is super easy and clean.


Sponsor: Make login Auth0’s problem. Not yours. Provide the convenient login features your customers want, like social login, multi-factor authentication, single sign-on, passwordless, and more. Get started for free.

Name Email (will show your gravatar icon) Home page (optional) 5+1=?

Comment (Some html is allowed: a@href@title, b, blockquote@cite, em, i, li, ol, pre, strike, strong, sub, super, u, ul) where the @ means "attribute." For example, you can use <a href="" title=""> or <blockquote cite="Scott">.   Live Comment Preview


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK