Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 453 Vote(s) - 3.6 Average
  • 1
  • 2
  • 3
  • 4
  • 5
How can I use Async with ForEach?

#1
Is it possible to use Async when using ForEach? Below is the code I am trying:

using (DataContext db = new DataLayer.DataContext())
{
db.Groups.ToList().ForEach(i => async {
await GetAdminsFromGroup(i.Gid);
});
}

I am getting the error:

>The name 'Async' does not exist in the current context

The method the using statement is enclosed in is set to async.
Reply

#2
The problem was that the `async` keyword needs to appear before the lambda, not before the body:

db.Groups.ToList().ForEach(async (i) => {
await GetAdminsFromGroup(i.Gid);
});
Reply

#3
This little extension method should give you exception-safe async iteration:

public static async Task ForEachAsync<T>(this List<T> list, Func<T, Task> func)
{
foreach (var value in list)
{
await func(value);
}
}

Since we're changing the return type of the lambda from `void` to `Task`, exceptions will propagate up correctly. This will allow you to write something like this in practice:

await db.Groups.ToList().ForEachAsync(async i => {
await GetAdminsFromGroup(i.Gid);
});

Reply

#4
Add this extension method

public static class ForEachAsyncExtension
{
public static Task ForEachAsync<T>(this IEnumerable<T> source, int dop, Func<T, Task> body)
{
return Task.WhenAll(from partition in Partitioner.Create(source).GetPartitions(dop)
select Task.Run(async delegate
{
using (partition)
while (partition.MoveNext())
await body(partition.Current).ConfigureAwait(false);
}));
}
}

And then use like so:


Task.Run(async () =>
{
var s3 = new AmazonS3Client(Config.Instance.Aws.Credentials, Config.Instance.Aws.RegionEndpoint);
var buckets = await s3.ListBucketsAsync();

foreach (var s3Bucket in buckets.Buckets)
{
if (s3Bucket.BucketName.StartsWith("mybucket-"))
{
log.Information("Bucket => {BucketName}", s3Bucket.BucketName);

ListObjectsResponse objects;
try
{
objects = await s3.ListObjectsAsync(s3Bucket.BucketName);
}
catch
{
log.Error("Error getting objects. Bucket => {BucketName}", s3Bucket.BucketName);
continue;
}

// ForEachAsync (4 is how many tasks you want to run in parallel)
await objects.S3Objects.ForEachAsync(4, async s3Object =>
{
try
{
log.Information("Bucket => {BucketName} => {Key}", s3Bucket.BucketName, s3Object.Key);
await s3.DeleteObjectAsync(s3Bucket.BucketName, s3Object.Key);
}
catch
{
log.Error("Error deleting bucket {BucketName} object {Key}", s3Bucket.BucketName, s3Object.Key);
}
});

try
{
await s3.DeleteBucketAsync(s3Bucket.BucketName);
}
catch
{
log.Error("Error deleting bucket {BucketName}", s3Bucket.BucketName);
}
}
}
}).Wait();

Reply

#5
Here is an actual working version of the above async foreach variants with sequential processing:

public static async Task ForEachAsync<T>(this List<T> enumerable, Action<T> action)
{
foreach (var item in enumerable)
await Task.Run(() => { action(item); }).ConfigureAwait(false);
}

Here is the implementation:

public async void SequentialAsync()
{
var list = new List<Action>();

Action action1 = () => {
//do stuff 1
};

Action action2 = () => {
//do stuff 2
};

list.Add(action1);
list.Add(action2);

await list.ForEachAsync();
}

What's the key difference? `.ConfigureAwait(false);` which keeps the context of main thread while async sequential processing of each task.
Reply

#6
The simple answer is to use the `foreach` keyword instead of the `ForEach()` method of `List()`.

using (DataContext db = new DataLayer.DataContext())
{
foreach(var i in db.Groups)
{
await GetAdminsFromGroup(i.Gid);
}
}
Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through