【问题标题】:How do I wait for a handler's response before continuing processing?在继续处理之前如何等待处理程序的响应?
【发布时间】:2019-10-27 21:19:31
【问题描述】:

我目前正在使用 Google Drive 的 .NET API,我正在尝试从我的驱动器上下载多个文件。 google 在他们的示例中使用的代码可以在here 找到(我的版本在下面)

在 .NET Core 控制台项目中,我正在遍历文件列表并尝试一次下载一个,如下所示:

foreach (var file in driveFiles) {
    var fileId = file.Id;
    var request = driveService.Files.Get(fileId);
    var stream = new System.IO.MemoryStream();

    // Add a handler which will be notified on progress changes.
    // It will notify on each chunk download and when the
    // download is completed or failed.
    request.MediaDownloader.ProgressChanged +=
        (IDownloadProgress progress) =>
    {
        switch (progress.Status)
        {
            case DownloadStatus.Downloading:
                {
                    Console.WriteLine(progress.BytesDownloaded);
                    break;
                }
            case DownloadStatus.Completed:
                {
                    Console.WriteLine("Download complete.");
                    break;
                }
            case DownloadStatus.Failed:
                {
                    Console.WriteLine("Download failed.");
                    break;
                }
        }
    };
    request.Download(stream);

    // .. carry on processing
}

我的问题是我有一个大约 300 个文件的列表。上面的代码同时触发了所有 300 次下载,我正在查看每次下载的进度。我想要发生的是每次下载一次发生一次,即。我启动了第一次下载,代码会等到下载完成后再进行下一次下载。

我尝试通过设置一个布尔值来做到这一点,该布尔值仅在下载完成或失败时更新,但这似乎不起作用:

foreach (var file in driveFiles) {
        var fileId = file.Id;
        var request = driveService.Files.Get(fileId);
        var stream = new System.IO.MemoryStream();

        bool processingComplete = false;

        // Add a handler which will be notified on progress changes.
        // It will notify on each chunk download and when the
        // download is completed or failed.
        request.MediaDownloader.ProgressChanged +=
            (IDownloadProgress progress) =>
        {
            switch (progress.Status)
            {
                case DownloadStatus.Downloading:
                    {
                        Console.WriteLine(progress.BytesDownloaded);
                        break;
                    }
                case DownloadStatus.Completed:
                    {
                        Console.WriteLine("Download complete.");
                        processingComplete = true;
                        break;
                    }
                case DownloadStatus.Failed:
                    {
                        Console.WriteLine("Download failed.");
                        processingComplete = true;
                        break;
                    }
            }
        };
        request.Download(stream);

        while (!processingComplete) ;

        processingComplete = false;
    }

但这似乎不起作用,代码似乎继续以相同的行为。

我有点不知道该怎么做。有人有什么想法吗?

【问题讨论】:

  • request.Download有对应的request.DownloadAsync方法吗?
  • 可以将每个下载的文件封装在一个Task中,之后就可以一个接一个的运行,这样就可以保证每次只下载一个文件。

标签: c# .net .net-core


【解决方案1】:

您的问题是您正在为每个文件启动一个单独的任务。即使我无法弄清楚您的代码的哪一部分实际上确实在这里进行了多任务处理。我在这里看不到任何明显的罪魁祸首,例如 await、Threads 等。您需要的是一项运行循环的任务。基本上,您必须等待请求完成,然后才能进入下一个 itteartion。

通常,执行“每个文件”多任务处理是没有好处的。通常瓶颈是磁盘或网络之类的东西。网络是一个边缘案例 - 它可以同时下载多个文件,即使从同一个端点下载多个文件也是有益的。使用 google API,它们可能由不同的服务器(geocasts IIRC)提供服务,提供者端可能存在带宽限制等。

【讨论】:

    【解决方案2】:

    因此,从 Fabio 的评论开始,似乎 request 确实有一个 DownloadAsync 方法。我已经实现了这个,这似乎为我解决了问题:

    foreach (var file in driveFiles) {
            var fileId = file.Id;
            var request = driveService.Files.Get(fileId);
            var stream = new System.IO.MemoryStream();
    
            // Add a handler which will be notified on progress changes.
            // It will notify on each chunk download and when the
            // download is completed or failed.
            request.MediaDownloader.ProgressChanged +=
                    (IDownloadProgress progress) =>
            {
                    switch (progress.Status)
                    {
                            case DownloadStatus.Downloading:
                                    {
                                            Console.WriteLine(progress.BytesDownloaded);
                                            break;
                                    }
                            case DownloadStatus.Completed:
                                    {
                                            Console.WriteLine("Download complete.");
                                            break;
                                    }
                            case DownloadStatus.Failed:
                                    {
                                            Console.WriteLine("Download failed.");
                                            break;
                                    }
                    }
            };
    
            IDownloadProgress result = await request.DownloadAsync(stream);    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-01-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-12
      • 1970-01-01
      相关资源
      最近更新 更多