I am a little confused by the behavior of my code [below]. I am working on a specialized, command line utility that downloads and processes some files. I am trying to use c#'s async functionality when possible. The code snippet runs as expected when the tasks are created and Task.WaitAll() is used. After the wait I have 2 tasks both of which have been marked as completed. The issue: My attempt to fetch the results from the tasks ends up running both tasks a second time! Why is this? How can I read the result without executing the task a second time?
private IEnumerable<Task<FileInfo>> DownloadFiles()
{
int fileCount = 1;
Console.Clear();
Console.SetCursorPosition(0, 0);
Console.Write("Download files...");
yield return DownloadFile(Options.SkuLookupUrl, "SkuLookup.txt.gz", fileCount++, f =>
{
return DecompressFile(f);
});
yield return DownloadFile(Options.ProductLookupUrl, "ProductList.txt.gz", fileCount++, f =>
{
return DecompressFile(f);
});
}
public void Execute()
{
var tasks = DownloadFiles();
Task.WaitAll(tasks.ToArray());
Console.WriteLine();
Console.WriteLine("Download(s) completed. Parsing sku lookup file.");
FileInfo[] files = tasks.Select(t => t.Result).ToArray(); // <-- triggers a second round of task execution
ParseSkuLookups(files.SingleOrDefault(f => f.Name.ToLowerInvariant().Contains("skulookup")));
}
And if relevant here is the download method:
private async Task<FileInfo> DownloadFile(string targetUrl, string destinationFile, int lineNumber, Func<FileInfo,FileInfo> callback = null)
{
FileInfo fi = new FileInfo(destinationFile);
if (!Options.NoCleanup || !fi.Exists)
{
WebClient client = new WebClient();
client.DownloadProgressChanged += (s, e) =>
{
char spinnerChar;
switch ((e.ProgressPercentage % 10))
{
case 0: spinnerChar = '|'; break;
case 1: spinnerChar = '/'; break;
case 2: spinnerChar = '-'; break;
case 3: spinnerChar = '|'; break;
case 4: spinnerChar = '\\'; break;
case 5: spinnerChar = '|'; break;
case 6: spinnerChar = '/'; break;
case 7: spinnerChar = '-'; break;
case 8: spinnerChar = '\\'; break;
default:
case 9: spinnerChar = '|'; break;
}
lock (ConsoleLockSync)
{
Console.SetCursorPosition(0, lineNumber);
Console.WriteLine(String.Format("{0} download: {1}% {2}",
destinationFile, e.ProgressPercentage==100 ? "[Complete]" : spinnerChar.ToString()));
}
};
await client.DownloadFileTaskAsync(new Uri(targetUrl, UriKind.Absolute), destinationFile);
}
else if(Options.NoCleanup)
{
lock (ConsoleLockSync)
{
Console.SetCursorPosition(0, lineNumber);
Console.WriteLine(String.Format("{0} download: Skipped [No Cleanup] ", destinationFile));
}
}
fi.Refresh();
return callback != null ? callback(fi) : fi;
}
C Introduction C is a general-purpose programming language created by Dennis Ritchie at the Bell Laboratories in 1972. It is a very popular language, despite being old. C is strongly associated with UNIX, as it was developed to write the UNIX operating system.
A low-level procedural language, C is designed to work across platforms and provide access to important features like memory management. C programming builds up the source code for many UNIX operating systems, compilers, video games, and even other computer programming languages like Python.
When you have a IEnumerable
implmented with a yield return
every time you enumerate the result it will re-run your function. tasks.ToArray()
in Task.WaitAll(tasks.ToArray());
enumerates it once then you enumerate it again in tasks.Select(t => t.Result).ToArray();
. To get it to enumerate once keep the result of the first ToArray()
call then use that result repeatedly throughout your method.
public void Execute()
{
var tasks = DownloadFiles();
var taskArray = tasks.ToArray();
Task.WaitAll(taskArray);
Console.WriteLine();
Console.WriteLine("Download(s) completed. Parsing sku lookup file.");
FileInfo[] files = taskArray.Select(t => t.Result).ToArray(); // <-- notice we use taskArray here instead of tasks.
ParseSkuLookups(files.SingleOrDefault(f => f.Name.ToLowerInvariant().Contains("skulookup")));
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With