【发布时间】:2015-02-12 14:06:51
【问题描述】:
我正在使用 .NET Framework v4.5。
我正在使用 MagickImage 库创建一种图像调整器。
用例:
用户上传大图(4k*4k 像素)并在不同地方使用不同尺寸(200*200 像素、1200*1200 像素)。
所以我通过调整大的大小并将它们存储在磁盘上来按需生成此类图像。
并发案例:用户上传图片,然后有几个用户请求该图片的缩略图。在那一刻,每个用户请求都开始创建调整大小的缩略图,因为它还不存在。当完成调整大小的第一个线程将其保存到磁盘时。由于文件已在使用中,所有其他线程都会出现异常。
在此之前它使用单线程并且不需要线程安全。
但现在它将用于基于 Web 的项目中,并发请求也是可能的。
当前的实现如下:
if (!FileExists(cachedImageFilepath))
{
byte[] resizedImage = _imageResizer.ResizeImage(originalImageFilepath, width, height);
_physicalFileManager.WriteToFile(cachedImageFilepath, resizedImage);
}
return cachedImageFilepath;
最简单的方法是在此操作周围使用锁定,但在这种情况下,Resizer 将在单个时间段内仅调整一张图像的大小。
我看到的另一个变体是创建类似于锁定机制的东西,它将通过字符串键锁定。
但无论如何,我发现在释放锁定后仔细检查文件是否存在的问题,例如:
if (!FileExists(cachedImageFilepath)){
lock(lockObjects[lockKey]){
if (!FileExists(cachedImageFilepath)){
}
}
}
有没有什么好的方法甚至 .NET 机制可以在没有开销的情况下做这样的事情?
【问题讨论】:
-
你有不同的线程同时访问同一个文件?
-
请定义并发请求?您可以使用基于文件的锁定机制(先独占打开写入文件,第一个打开它的人 - 完成工作,其他人 - 跳过),这意味着您不需要内存锁定。
-
@YuvalItzchakov 是的,问题是他们都开始创建相同大小的缩略图(保存相同的文件)
-
互斥锁是解决方案
-
您可以创建一个临时文件并在完成后将其重命名为目标名称。如果重命名失败,则丢弃临时文件,因为目标文件已经存在。应该在 Windows + NTFS 上工作,但我不能 100% 确定这种方法在某些文件系统/操作系统上是否安全。
标签: c# .net multithreading thread-safety