Ich habe eine einzige Methode, die einen Dateinamen eines Bildes und verarbeitet das Bild (CPU-intensiv), dann lädt es in BLOB-Speicher (async IO). Hier ist eine Zusammenfassung der Methode:Welcher dieser Ansätze zur Parallelisierung einer asynchronen Methode ist am besten geeignet?
public async Task<ImageJob> ProcessImage(String fileName) {
Byte[] imageBytes = await ReadFileFromDisk(fileName).ConfigureAwait(false); // IO-bound
Byte[] processedImage = RunFancyAlgorithm(imageBytes); // CPU-bound
Uri blobUri = await this.azureBlobClient.UploadBlob(processedImage).ConfigureAwait(false); // IO-bound
return new ImageJob(blobUri);
}
Der andere Teil meines Programms erhält eine Liste von Tausenden von Dateinamen verarbeitet werden.
Wie kann ich meine Methode ProcessImage
so aufrufen, dass die verfügbare IO- und CPU-Leistung maximal genutzt wird?
Ich habe sechs verschiedene Arten (bisher) identifiziert meine Methode zum Aufruf - aber ich bin nicht sicher, was das Beste ist:
String[] fileNames = GetFileNames(); // typically contains thousands of filenames
// Approach 1:
{
List<Task> tasks = fileNames
.Select(fileName => ProcessImage(fileName))
.ToList();
await Task.WhenAll(tasks);
}
// Approach 2:
{
List<Task> tasks = fileNames
.Select(async fileName => await ProcessImage(fileName))
.ToList();
await Task.WhenAll(tasks);
}
// Approach 3:
{
List<Task> tasks = new List<Task>();
foreach(String fileName in fileNames)
{
Task imageTask = ProcessImage(fileName);
tasks.Add(imageTask);
}
await Task.WhenAll(tasks);
}
// Approach 4 (Weirdly, this gives me this warning: CS4014 "Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call."
// ...even though I don't use an async lambda in the previous 3 examples, why is Parallel.ForEach so special?
{
ParallelLoopResult parallelResult = Parallel.ForEach(fileNames, fileName => ProcessImage(fileName));
}
// Approach 5:
{
ParallelLoopResult parallelResult = Parallel.ForEach(fileNames, async fileName => await ProcessImage(fileName));
}
// Approach 6:
{
List<Task> tasks = fileNames
.AsParallel()
.Select(fileName => ProcessImage(fileName))
.ToList();
await Task.WhenAll(tasks);
}
// Approach 7:
{
List<Task> tasks = fileNames
.AsParallel()
.Select(async fileName => await ProcessImage(fileName))
.ToList();
await Task.WhenAll(tasks);
}
je mischen async/erwarten und und 'Parallel.ForEach' sie sind unvereinbar, Es bewirkt, dass Sie eine Async-Void-Funktion generieren. Sie müssen [TPL stattdessen] (https://msdn.microsoft.com/en-us/library/dd460717 (v = vs.110) .aspx) –
für Ihre Warnmeldung (Ansatz 4) verwenden. Hier finden Sie eine Erklärung: https://blogs.msdn.microsoft.com/ericlippert/2010/11/11/asynchronyin-in-c-5-part-six-whither-async/. Kurz gesagt, das 'async' Schlüsselwort aktiviert das' await' Schlüsselwort, dh wenn Sie das 'await' Schlüsselwort verwenden möchten, muss Ihre Methode' async' sein, das bedeutet nicht, dass Sie 'wait' nicht verwenden müssen, wenn Ihre Methode ist nicht "asynchron". –
@KhanhTO Ich weiß das - aber aus irgendeinem Grund warnt der Compiler mich in Ansatz 4, warnt mich aber nicht in Ansatz 1, obwohl das Lambda identisch ist. – Dai