问题
Originally, I had the following:
foreach (Product product in products)
{
product.ImageUri = _imageClient.GetImageUri(product.GetImagePath());
}
What I would like to do is process all of the Products in parallel rather than one at a time. I have updated _imageClient.GetImageUri(...) to _imageClient.GetImageUriAsync(...). I can now do the following:
List<Task<Uri>> tasks = new List<Task<Uri>>();
foreach (Product product in products)
{
Task<Uri> task = _imageClient.GetImageUriAsync(product.GetImagePath());
tasks.Add(task);
}
var results = await Task.WhenAll(tasks);
The problem I have with this approach is that I now have to loop through the results, match each to the correct Product and assign the property.
Is there a way to combine the two approaches so that I can perform the property assignment as part of the task so that all can be run in parallel?
回答1:
What about:
List<Task<Uri>> tasks = new List<Task<Uri>>();
foreach (Product product in products)
{
tasks.Add(Task.Run( async () => product.ImageUri = await _imageClient.GetImageUriAsync(product.GetImagePath()) ));
}
await Task.WhenAll(tasks);
You don't even really need the results in the end.
回答2:
you could start them also in a single select statement and await them in the same line:
await Task.WhenAll(products.Select(async p => p.ImageUri = await _imageClient.GetImageUriAsync(p.GetImagePath())));
This will execute all tasks in parallel and initialize the property. Task.WhenAll will then wait for the slowest of them.
Here is a LINQPad Example to demonstrate the workings:
void Main()
{
Do();
}
public async Task Do()
{
List<Product> products = new List<UserQuery.Product>
{
new Product(),
new Product(),
new Product(),
new Product(),
};
Stopwatch sw = new Stopwatch();
Console.WriteLine("START");
sw.Start();
await Task.WhenAll(products.Select(async x => x.MyProperty = await GetNumber()));
sw.Stop();
Console.WriteLine($"ENDE: {sw.ElapsedMilliseconds}");
products.Dump();
}
public async Task<int> GetNumber()
{
Random rand = new Random(DateTime.Now.Millisecond);
return await Task.Run(() => { System.Threading.Thread.Sleep(4000); return rand.Next(1,1000);});
}
class Product
{
public int MyProperty { get; set; }
}
Output:
来源:https://stackoverflow.com/questions/57457470/task-property-assignment