在VB.NET中保存数千个文件的最快方法?
我每秒下载数千个文件。每个文件大约5KB,总下载速度约为200Mb/s。我需要保存所有这些文件 下载过程分为数千个正在运行的异步任务。当他们下载完一个文件并想要保存它时,他们会将它添加到一个要保存的文件队列中 下面是这门课的内容。我在一开始就创建了这个类的一个实例,并让我的任务添加需要保存到队列中的文件在VB.NET中保存数千个文件的最快方法?,.net,vb.net,performance,file,file-io,.net,Vb.net,Performance,File,File Io,我每秒下载数千个文件。每个文件大约5KB,总下载速度约为200Mb/s。我需要保存所有这些文件 下载过程分为数千个正在运行的异步任务。当他们下载完一个文件并想要保存它时,他们会将它添加到一个要保存的文件队列中 下面是这门课的内容。我在一开始就创建了这个类的一个实例,并让我的任务添加需要保存到队列中的文件 Public Class FileSaver Structure FileToSave Dim path As String Dim data() As Byte End St
Public Class FileSaver
Structure FileToSave
Dim path As String
Dim data() As Byte
End Structure
Private FileQueue As New Concurrent.BlockingCollection(Of FileToSave)
Sub New()
Task.Run(
Async Function()
While 1
Dim fl As FileToSave = FileQueue.Take()
Using sourceStream As New FileStream(fl.path, FileMode.Append, FileAccess.Write, FileShare.None, bufferSize:=4096, useAsync:=True)
Await sourceStream.WriteAsync(fl.data, 0, fl.data.Length)
End Using
End While
End Function
)
End Sub
Public Sub Add(path As String, data() As Byte)
Dim fl As FileToSave
fl.path = path
fl.data = data
FileQueue.Add(fl)
End Sub
Public Function Count()
Return FileQueue.Count
End Function
End Class
该类只有一个实例,只有一个队列。每个任务不会创建单独的队列。这个类有一个全局实例和一个内部队列,我的所有任务都将文件添加到这个队列中
此后,我将ConcurrentQueue
替换为默认的BlockingCollection
,它应该像ConcurrentQueue
一样工作,但允许我从集合中执行阻塞Take()
,而不必不断循环
我使用的硬盘支持大约180MB/s的最大读/写速度。我的下载速度只有200Mb/s,而且随着队列的不断增长,我似乎无法足够快地保存数据。有点不对劲,我似乎不知道是什么
这是最好(最快)的方法吗?我能在这里做些改进吗
编辑:这个问题被搁置了,我不能用我的答案发表我自己的答案。我会把它贴在这里 这里的问题是,虽然写入文件是一个相对便宜的过程,但打开文件进行写入却不是。因为我下载了数千个文件,所以我分别保存每个文件,这严重影响了性能 我所做的是将多个下载的文件(当它们仍在RAM中时)组合成一个文件(带分隔符),并将该文件写入磁盘。我正在下载的文件有一些属性,允许以这种方式对它们进行逻辑分组,并在以后继续使用。比例约为100:1 我似乎不再受写限制,而且我目前正在以~40MB/s的速度保存,如果我达到另一个过早的限制,我会更新这个。希望这对别人有帮助
EDIT2:我的目标是更快的IO 由于我现在将多个文件合并为一个文件,这意味着我总共要执行一个打开(CreateFile)操作,然后对一个打开的文件进行多次写入。这是好的,但仍然不是最优的。一次10MB写入比十次1MB写入更好。多次写入速度较慢,并会导致磁盘碎片,从而降低读取速度。不太好 因此,解决方案是将所有(或尽可能多的)下载的文件缓冲在RAM中,然后一旦达到某个点,通过一次写入操作将它们全部写入单个文件。我有大约50GB的RAM,所以这对我来说非常有用 然而,现在还有另一个问题。由于我现在手动缓冲写数据以尽可能少地执行写操作,Windows缓存变得有些冗余,实际上开始降低速度,并消耗RAM。让我们把它处理掉 解决方案是执行无缓冲(异步)I/O,这是Windows的CreateFile()支持的。但在.NET中不容易支持。我必须使用一个图书馆(似乎唯一存在的图书馆)来完成这项工作,你可以在这里找到: 这允许从.NET进行简单的无缓冲异步IO。唯一的要求是您现在必须手动对字节()缓冲区进行扇区对齐,否则WriteFile()将失败并出现“无效参数”错误。在我的例子中,这只需要将缓冲区调整为512的倍数
在所有这些之后,我的驱动器的写入速度达到了~110MB/s。比我预想的要好得多。我建议你调查一下。看起来您想创建一个新的 在当前实现中使用TPL数据流的好处在于您可以。这将允许您使用数字来优化您的解决方案,以满足您的需求 正如@Graffito提到的,如果您使用的是旋转盘片,那么写入可能会受到并发写入的文件数量的限制,这使得这是一个尝试和错误,以获得最佳的调优性能 当然,您可以编写自己的机制来限制并发性 我希望这会有所帮助
[补充]我在一家公司工作,该公司归档的电子邮件具有类似的磁盘写入要求。当一个目录中有太多文件时,该公司的io速度出现问题。因此,他们选择将每个目录中的文件限制为1000个文件/文件夹。那个决定是在我之前做出的,但可能与你的项目有关 您的磁盘IO子系统是否支持200MB/s?请阅读并观察,在构造函数中执行I/O本身就是一种糟糕的做法。@Remus,可能不是。但我也不会以200MB/s的速度下载。如果文件复制到一个硬盘上,而不是SSD上,那么并行写入文件会降低性能,而不会因为磁头移动而提高性能。如果有多个目标磁盘,则每个磁盘使用一个线程。