gpt4 book ai didi

c# - 如何在 C# 中以线程安全的方式读取/生成+读取文件

转载 作者:太空狗 更新时间:2023-10-29 19:45:17 29 4
gpt4 key购买 nike

我正在使用 .NET Framework v4.5

我正在使用 MagickImage 库创建一种图像缩放器。


用例:

用户上传大图(4k*4k像素)并在不同地方使用不同尺寸(200*200像素,1200*1200像素)。

因此,我通过调整大图像的大小并将它们存储在磁盘上来按需生成此类图像。

并发情况:用户上传图片,然后几个用户请求这张图片的缩略图。在那一刻,每个用户请求开始创建调整大小的缩略图,因为它还不存在。当第一个完成调整大小的线程将其保存到磁盘。由于文件已在使用中,所有其他线程都将出现异常。


在那之前它使用单线程并且不需要线程安全。

但现在它会被用在一个基于网络的项目中,而且并发请求也是可能的

当前的实现是这样的:

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 机制可以在没有开销的情况下做这样的事情?

最佳答案

看来您需要的是一个线程安全的缩略图管理器。 IE。一个本身了解如何协调对文件的访问的类。

一个简单的版本可能是这样的:

class ThumbnailManager
{
private Dictionary<Tuple<string, int, int>, string> _thumbnails =
new Dictionary<Tuple<string, int, int>, string>();
private Dictionary<Tuple<string, int, int>, Task<string>> _workers =
new Dictionary<Tuple<string, int, int>, Task<string>>();
private readonly object _lock = new object();

public async Task<string> RetrieveThumbnail(string originalFile, int width, int height)
{
Tuple<string, int, int> key = Tuple.Create(originalFile, width, height);
Task task;

lock (_lock)
{
string fileName;

if (_thumbnails.TryGetValue(key, out fileName))
{
return fileName;
}

if (!_workers.TryGetValue(key, out task))
{
task = Task.Run(() => ResizeFile(originalFile, width, height));
_workers[key] = task;
}
}

string result = await task;

lock (_lock)
{
_thumbnails[key] = result;
_workers.Remove(key);
}

return result;
}
}

string ResizeFile(string originalImageFilepath, int width, int height)
{
string cachedImageFilepath = GenerateCachedImageFilepath(originalImageFilepath);

if (!FileExists(cachedImageFilepath))
{
byte[] resizedImage = _imageResizer.ResizeImage(originalImageFilepath, width, height);

_physicalFileManager.WriteToFile(cachedImageFilepath, resizedImage);
}

return cachedImageFilepath;
}

换句话说,首先管理器检查它是否知道必要的文件。如果是,则意味着文件已经创建,它只是返回路径。

如果没有,那么接下来它会检查是否正在创建必要的文件。毕竟,多次创建同一个文件毫无意义!如果它还没有在进行中,那么它会启动一个 Task 来制作文件。如果它已经在进行中,那么它只是检索表示该操作的 Task

无论哪种情况,都等待表示操作的Task。该方法在那一点返回;操作完成后,该方法恢复执行,将生成的文件的名称添加到已完成文件的字典中,并从正在进行的字典中删除已完成的任务。

当然,它是一个async方法,调用者使用this的正确方法是它自己在调用它时使用await,这样方法就可以如果需要异步完成而不阻塞调用线程。您的问题中没有足够的上下文来确切地知道那会是什么样子,但我想您可以弄清楚那部分。

关于c# - 如何在 C# 中以线程安全的方式读取/生成+读取文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28479525/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com