我对我的代码的行为有些困惑[下面]。我正在开发一个专门的命令行工具,用于下载和处理一些文件。我尝试在可能的情况下使用c#的异步功能。当创建任务并使用Task.WaitAll()时,代码片段按预期运行。等待之后,我有两个任务都被标记为完成。问题:我试图从任务中获取结果最终会再次运行两个任务!为什么是这样?如何在不执行第二次任务的情况下读取结果?完成的c#任务再次运行...为什么?
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")));
}
如果相关这里是下载方法:
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;
}
哦,顺便说一句。调用'.WaitAll('在异步方法上很容易让你死锁,你应该让Execute返回一个'async Task'并且执行一个'await Task.WhenAll(tasks)'或者用来使用'.ConfigureAwait(false) ''DownloadFile'内每等待电话# –
两个答案的价格一...这是一个控制台应用程序,但是,所以我不过分关注死锁,但这将是有用的信息在其他地方,我再次感谢! –