Parallel.ForEach 使用 WebClient 时出错
本文关键字:出错 WebClient 使用 ForEach Parallel | 更新日期: 2023-09-27 18:36:49
首先,我的免责声明:我是一个平行菜鸟。我以为这是一个容易解决的"令人尴尬的平行"问题,但它让我陷入了循环。
我正在尝试从网上并行下载一些照片。原始照片是高分辨率的,占用了相当多的空间,所以我将在下载后压缩它们。
代码如下:
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);
}
所以这就是事情让我感到困惑的地方:每张照片都命中 SavePhotoFile() 方法的 Catch{} 块webClient.DownloadFile
行。错误消息是 WebClient 请求期间发生的异常,内部详细信息是"进程无法访问文件...... -original.jpg因为它正被另一个进程使用。
如果我对这个错误不够困惑,我对接下来发生的事情更加困惑。事实证明,如果我只是忽略消息并等待,图像最终将下载并进行处理。
这是怎么回事?
好的,所以在我对并行性的关注中,我犯了一个简单的错误:我对我的数据假设了一些不正确的东西。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();
}