gpt4 book ai didi

.net - 在 VB.NET 中保存数千个文件的最快方法?

转载 作者:行者123 更新时间:2023-12-04 12:47:00 26 4
gpt4 key购买 nike

关闭。这个问题是opinion-based .它目前不接受答案。












想改善这个问题吗?更新问题,以便可以通过 editing this post 用事实和引文回答问题.

6年前关闭。




Improve this question




我每秒下载数千个文件。每个文件约5KB,总下载速度约200Mb/s。我需要保存所有这些文件。

下载过程分为数千个正在运行的不同异步任务。当他们完成下载文件并想要保存它时,他们将它添加到要保存的文件队列中。

这是这个类的样子。我一开始就创建了这个类的一个实例,并让我的任务添加需要保存到队列中的文件。

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 的目标上取得更多进展。

由于我现在将多个文件合并为一个,这意味着我总共执行 1 个打开 (CreateFile) 操作,然后多次写入打开的文件。这很好,但仍然不是最佳的。最好进行一次 10MB 写入而不是十次 1MB 写入。多次写入速度较慢,并导致磁盘碎片化,随后也会减慢读取速度。不好。

因此,解决方案是在 RAM 中缓冲所有(或尽可能多)下载的文件,然后一旦达到某个点,通过一次写入操作将它们全部写入单个文件。我有大约 50GB 的 RAM,所以这对我很有用。

然而,现在还有另一个问题。由于我现在手动缓冲我的写入数据以尽可能少地执行写入操作,因此 Windows 缓存变得有些多余,实际上开始减慢速度并消耗 RAM。让我们摆脱它。

对此的解决方案是进行无缓冲(和异步)I/O,Windows 的 CreateFile() 支持该 I/O。但在 .NET 中不容易支持。我不得不使用一个库(似乎是唯一一个)来完成这个,你可以在这里找到: http://programmingaddicted.blogspot.com/2011/05/unbuffered-overlapped-io-in-net.html

这允许来自 .NET 的简单无缓冲异步 IO。唯一的要求是您现在必须手动对 byte() 缓冲区进行扇区对齐,否则 WriteFile() 将因“无效参数”错误而失败。在我的情况下,这只是需要将我的缓冲区对齐到 512 的倍数。

在这一切之后,我的驱动器写入速度达到了 ~110MB/s。比我预期的要好得多。

最佳答案

我建议您查看 TPL DataFlow .看起来您要创建一个 producer/consumer .

在您当前的实现中使用 TPL DataFlow 的好处在于您可以 Specify the degree of parallelism .这将允许您使用数字来最好地调整您的解决方案以满足您的需求。

正如@Graffito 所提到的,如果您使用的是旋转盘片,则写入可能会受到同时写入的文件数量的限制,这使得这成为最佳调整性能的反复试验。

当然,您可以编写自己的机制来限制并发。

我希望这个对你有用。

[附加] 我在一家存档电子邮件的公司工作,该公司对写入磁盘有类似的要求。当目录中有太多文件时,该公司会遇到 io 速度问题。因此,他们选择将文件限制为每个目录 1000 个文件/文件夹。这个决定在我之前,但可能与您的项目有关。

关于.net - 在 VB.NET 中保存数千个文件的最快方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31391652/

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