【问题标题】:Parallel.ForEach Error when using WebClient使用 WebClient 时出现 Parallel.ForEach 错误
【发布时间】:2012-06-11 02:24:10
【问题描述】:

首先,我的免责声明:我是一个平行的菜鸟。我认为这将是一个容易解决的“令人尴尬的并行”问题,但它让我陷入了循环。

我正在尝试从网络上并行下载一些照片。原始照片是高分辨率的,占用空间很大,所以我会在下载后压缩它们。

代码如下:

    private static void DownloadPhotos(ISet<MyPhoto> photos)
    {
        List<MyPhoto> failed = new List<MyPhoto>();

        DateTime now = DateTime.Now;
        string folderDayOfYear = now.DayOfYear.ToString();
        string folderYear = now.Year.ToString();
        string imagesFolder = string.Format("{0}{1}\\{2}\\", ImagePath, folderYear, folderDayOfYear);

        if (!Directory.Exists(imagesFolder))
        {
            Directory.CreateDirectory(imagesFolder);
        }

        Parallel.ForEach(photos, photo =>
        {
            if (!SavePhotoFile(photo.Url, photo.Duid + ".jpg", imagesFolder))
            {
                failed.Add(photo);
                Console.WriteLine("adding to failed photos: {0} ", photo.Duid.ToString());
            }
        });

        Console.WriteLine();
        Console.WriteLine("failed photos count: {0}", failed.Count);

        RemoveHiResPhotos(string.Format(@"{0}\{1}\{2}", ImagePath, folderYear, folderDayOfYear));
    }


    private static bool SavePhotoFile(string url, string fileName, string imagesFolder)
    {
        string fullFileName = imagesFolder + fileName;
        string originalFileName = fileName.Replace(".jpg", "-original.jpg");
        string fullOriginalFileName = imagesFolder + originalFileName;

        if (!File.Exists(fullFileName))
        {
            using (WebClient webClient = new WebClient())
            {
                try
                {
                    webClient.DownloadFile(url, fullOriginalFileName);
                }
                catch (Exception ex)
                {
                    Console.WriteLine();
                    Console.WriteLine("failed to download photo: {0}", fileName);
                    return false;
                }
            }
            CreateStandardResImage(fullOriginalFileName, fullOriginalFileName.Replace("-original.jpg", ".jpg"));
        }
        return true;
    }

    private static void CreateStandardResImage(string hiResFileName, string stdResFileName)
    {
        Image image = Image.FromFile(hiResFileName);
        Image newImage = image.Resize(1024, 640);
        newImage.SaveAs(hiResFileName, stdResFileName, 70, ImageFormat.Jpeg);
    }

这就是让我感到困惑的地方:每张照片都在 webClient.DownloadFile 行的 SavePhotoFile() 方法的 Catch{} 块中命中。错误消息是在 WebClient 请求期间发生的异常,内部详细信息是“进程无法访问文件...... -original.jpg,因为它正在被另一个进程使用。”

如果我对这个错误还不够困惑,那么接下来会发生什么让我更加困惑。事实证明,如果我只是忽略消息并等待,图像最终会下载并被处理。

发生了什么事?

【问题讨论】:

  • 什么是 Duid?我假设因为它被传递到 fileName 参数中,所以它是文件名并且是唯一的?另外,异常的数量是否等于列表中的文件数量?
  • 这是一个识别文件的 guid。
  • 不,通过目视查看输出文件夹,如果照片文件足够小以至于它们可以快速加载,那么这些文件不会被添加到错误计数中。
  • 根据docs对源可枚举中的每个元素调用一次主体委托。它与当前元素一起作为参数提供。 您可以尝试的一件事是在保存文件名时添加一个随机数。通过这种方式,您可以看到 1)每个文件有多少,以及 2)如果由于某种原因 Duid 不像您想象的那么独特。

标签: c# webclient parallel.foreach


【解决方案1】:

好的,所以在我对并行性的关注中,我犯了一个简单的错误:我假设我的数据不正确。 Brianestey 发现了问题所在:Duid 并不是独一无二的。它应该是唯一的,除了在创建列表的过程中缺少一些代码。

解决方法是将其添加到 MyPhoto 类中

    public override bool Equals(object obj)
    {
        if (obj is MyPhoto)
        {
            var objPhoto = obj as MyPhoto;
            if (objPhoto.Duid == this.Duid)
                return true;
        }
        return false;
    }

    public override int GetHashCode()
    {
        return this.Duid.GetHashCode();
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-11-12
    • 1970-01-01
    • 2012-11-18
    • 2017-01-11
    • 2015-09-11
    • 2021-07-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多