【问题标题】:C# Task.WaitAll isn't waitingC# Task.WaitAll 不等待
【发布时间】:2016-09-12 01:45:32
【问题描述】:

我的目标是从 Amazon Web Services 存储桶中下载图像。

我有以下代码功能,可以一次下载多张图片:

public static void DownloadFilesFromAWS(string bucketName, List<string> imageNames)
{
    int batchSize = 50;
    int maxDownloadMilliseconds = 10000;

    List<Task> tasks = new List<Task>();

    for (int i = 0; i < imageNames.Count; i++)
    {
        string imageName = imageNames[i];
        Task task = Task.Run(() => GetFile(bucketName, imageName));
        tasks.Add(task);
        if (tasks.Count > 0 && tasks.Count % batchSize == 0)
        {
            Task.WaitAll(tasks.ToArray(), maxDownloadMilliseconds);//wait to download
            tasks.Clear();
        }
    }

    //if there are any left, wait for them
    Task.WaitAll(tasks.ToArray(), maxDownloadMilliseconds);
}

private static void GetFile(string bucketName, string filename)
{
    try
    {
        using (AmazonS3Client awsClient = new AmazonS3Client(Amazon.RegionEndpoint.EUWest1))
        {
            string key = Path.GetFileName(filename);

            GetObjectRequest getObjectRequest = new GetObjectRequest() {
                 BucketName = bucketName,
                    Key = key
            };

            using (GetObjectResponse response = awsClient.GetObject(getObjectRequest))
            {
                string directory = Path.GetDirectoryName(filename);
                if (!Directory.Exists(directory))
                {
                    Directory.CreateDirectory(directory);
                }

                if (!File.Exists(filename))
                {
                    response.WriteResponseStreamToFile(filename);
                }
            }
        }
    }
    catch (AmazonS3Exception amazonS3Exception)
    {
        if (amazonS3Exception.ErrorCode == "NoSuchKey")
        {
            return;
        }
        if (amazonS3Exception.ErrorCode != null && (amazonS3Exception.ErrorCode.Equals("InvalidAccessKeyId") || amazonS3Exception.ErrorCode.Equals("InvalidSecurity")))
        {
            // Log AWS invalid credentials
            throw new ApplicationException("AWS Invalid Credentials");
        }
        else
        {
            // Log generic AWS exception
            throw new ApplicationException("AWS Exception: " + amazonS3Exception.Message);
        }
    }
    catch
    {
        //
    }
}

图像的下载一切正常,但Task.WaitAll 似乎被忽略了,其余代码继续执行——这意味着我尝试获取当前不存在的文件(因为它们还没有下载)。

我发现this 对另一个问题的答案似乎与我的相同。我尝试使用答案来更改我的代码,但它仍然不会等待下载所有文件。

谁能告诉我哪里出错了?

【问题讨论】:

  • 您不应该先添加所有下载任务,然后然后等待它们完成吗?我就是这样做的。您正在做的方式 - 在池中放置一个新线程后立即等待它完成 - 看起来像同步编程 - 换句话说,您没有从多线程中获得任何好处。这与 不等待 没有直接关系,但是......我作为评论离开了。
  • @Veverke 我是 Tasks 的新手,所以我想如果我将它们全部添加,假设我需要下载 10,000 个文件,所有任务会同时运行并且对于系统处理??? - 出于这个原因,我决定分批运行任务。
  • 好吧,我错过了你有 2 个等待的事实,我只看到了第一个。然后我现在问别的问题:为什么你需要循环内的那个?你试过没有它就跑一次吗?尝试在 for 循环中注释 if 并看看会发生什么。你有例外吗?
  • 关于您的评论 - 操作系统可以有效地处理大量线程,除此之外的所有内容不仅不会带来好处,而且会由于任务处理开销(上下文切换)而降低性能等) - 但我不知道这个数字是多少。它还取决于您的任务完成/处理时间估计所需的时间。如果他们应该在 5 秒内完成他们的工作,那么您应该能够同时处理更多的任务,而不是每个都必须花费 5 分钟。
  • 批处理实际上可能是一件好事,因为您最有可能首先花费的不是可以同时运行的任务数量,而是与网络服务和带宽。

标签: c# task


【解决方案1】:

代码按预期运行。 Task.WaitAll 在 10 秒后返回,即使不是所有文件都已下载,因为您在变量 maxDownloadMilliseconds 中指定了 10 秒(10000 毫秒)的超时时间。

如果您真的想等待所有下载完成,请致电Task.WaitAll 而不指定超时。

使用

Task.WaitAll(tasks.ToArray());//wait to download

在这两个地方。

要查看有关如何在不对系统造成压力的情况下实现并行下载的一些很好的解释(只有最大数量的并行下载),请参阅How can I limit Parallel.ForEach?的答案

【讨论】:

  • 未完成的任务不会中止,WaitAll 只是返回,而任务继续在后台运行。
  • 如果你想让任务中止,你必须在这个游戏中带一个 CancellationToken :o)
  • @NineBerry 它不会中止它们。如果任务仍在执行,它只会返回 false,您可以选择继续等待或手动取消它们。
  • 任务的最终状态是 RanToCompletion、Canceled 或 Faulted
  • 当任务发生异常时,任务函数完成,因此认为任务完成。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-16
  • 2016-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-19
相关资源
最近更新 更多