在没有附加visual studio调试器的情况下,Task.WWhenAll()无法按预期工作



我有一个关于异步编程和Task.WWhenAll((的问题。我有一段代码片段,可以从谷歌驱动器下载一个文件夹,当我调试代码时,它可以正常工作。但是,当我在没有调试器的情况下运行应用程序时,下载函数所花费的时间至少是使用调试器运行时的4倍。我还得到了带有TaskCancelled异常的崩溃日志(System.Threading.Tasks.TaskCanceledException:一个任务被取消。(,这些异常在附加调试器时不会发生。为了使代码在没有附加调试器的情况下按预期工作,需要更改的内容。注意,这个片段在使用调试器的情况下下载+-1000个文件大约22-25秒,在不使用调试器的条件下下载2min+。

public static async Task<bool> DownloadFolder(CloudDataModel.File file, string path, params string[] exclude)
{
try
{
if (file != null && !string.IsNullOrEmpty(file.id))
{
List<string> toExclude = new List<string>();
if(exclude != null)
{
toExclude = exclude.ToList();
}

List<Task> downloadFilesTask = new List<Task>();
var files = await file.GetFiles();
foreach (var f in files)
{
var task = f.Download(path);
downloadFilesTask.Add(task);
}

var folders = await file.GetFoldersAsync();
foreach (var folder in folders)
{
if (toExclude.Contains(folder.name))
{
continue;
}
Task task = null;
if (path.Equals(Statics.ProjectFolderName))
{
task = DownloadFolder(folder, folder.name);
}
else
{
task = DownloadFolder(folder, Path.Combine(path, folder.name));
}

downloadFilesTask.Add(task);
}
var array = downloadFilesTask.ToArray();
await Task.WhenAll(array);
return true;
}                
}
catch (Exception e)
{
Crashes.TrackError(e);
}
return false;
}

编辑

经过更多的尝试和错误,故障已经被识别。文件的下载是出现意外行为的原因

public static async Task<StorageFile> DownloadFile(CloudDataModel.File file, string destinationFolder)
{
try
{

if (file != null)
{
Debug.WriteLine($"start download {file.name}");
if (file.mimeType == Statics.GoogleDriveFolderMimeType)
{
Debug.WriteLine($"did not download resource,  resource was folder instead of file. mimeType: {file.mimeType}");
return null;
}
var endpoint = Path.Combine(DownloadFileEndpoint, $"{file.id}?alt=media");
// this would cause the unexpected behaviour
HttpResponseMessage response = await client.GetAsync(endpoint);



StorageFile downloadedFile;
using (Stream streamToReadFrom = await response.Content.ReadAsStreamAsync())
{
var memstream = new MemoryStream();
StreamReader reader = new StreamReader(streamToReadFrom);
streamToReadFrom.Position = 0;
await streamToReadFrom.CopyToAsync(memstream);
downloadedFile = await fileHandler.SaveDownloadedCloudFile(memstream, file, destinationFolder);
Debug.WriteLine($"download finished {file.name}");
}
return downloadedFile;
}
return null;
}
catch (Exception e)
{
Crashes.TrackError(e);
return null;
}
}

在为客户端(System.Net.Http.HttpClient(设置超时后,代码按预期执行。

client.Timeout = new TimeSpan(0,0,5);

因此,经过一些尝试和错误,文件的下载被确定为问题的原因。

var task = f.Download(path);

Download函数实现了一个System.Net.Http.HttpClient,它在没有任何超时的情况下被初始化。当其中一个任务超时时,所有其他任务也不会按预期执行。为了解决这个问题,向HttpClient对象添加了5秒的超时。

private static void InitializeClient()
{
HttpClientHandler handler = new HttpClientHandler { AllowAutoRedirect = true };
client = new HttpClient(handler);
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", AccountManager.LoggedInAccount.Token);
client.Timeout = new TimeSpan(0,0,5);
}

此更改之后,代码将按预期执行。

我的猜测是,如果没有调试器,并行度会增加,因此远程服务器被请求溢出,无法以最佳方式执行。您的代码没有任何限制并发/并行度的规定。解决此问题的一种可能方法是使用SemaphoreSlim,如本问题(以及其他许多问题(所示。

最新更新