0

我有一个生成一些输出的服务器,如下所示:http://192.168.0.1/getJPG=[ID]

我必须通过 ID 1 到 20M。

我看到大部分延迟都在存储文件中,目前我确实将每个请求结果作为一个单独的文件存储在一个文件夹中。格式为:[ID].jpg

服务器响应很快,生成器服务器真的很快,但我无法快速处理接收到的数据。

存储数据以供以后处理的最佳方式是什么?

我可以做所有类型的存储,比如在数据库中,比如在单个文件中,然后再解析大文件等。

我可以用 .NET、PHP、C++ 等编写代码。对编程语言没有限制。请指教。

谢谢

4

4 回答 4

2

因此,您正在从服务器下载 2000 万个文件,而将它们保存到磁盘的速度是一个瓶颈?如果您通过 Internet 访问服务器,那就很奇怪了。也许您正在通过本地网络下载,或者“服务器”甚至在本地运行。

有 2000 万个文件要保存,我确信它们不会全部放入 RAM,因此在内存中缓冲数据也无济于事。如果将数据写入磁盘的最大速度确实是一个瓶颈,那么使用 MS SQL 或任何其他 DB 不会改变任何东西。数据库没有什么“魔法”——它受到磁盘性能的限制,就像任何其他程序一样。

听起来您最好的选择是使用多个磁盘。并行下载多个文件,并在收到每个文件后,以循环方式将其写入不同的磁盘。您拥有的磁盘越多越好。使用多线程或非阻塞 I/O,因此下载和磁盘写入都同时发生。

于 2013-01-03T00:01:58.667 回答
1

可能它有助于按顺序访问磁盘。这是一个简单的技巧:将所有传入的文件流式传输到一个未压缩的 ZIP 文件(有相应的库)。这使得所有 IO 都是顺序的,并且只有一个文件。您还可以在大约 10000 张图像后拆分一个新的 ZIP 文件,以保持单个 ZIP 较小。

您可以稍后通过从 ZIP 文件流式传输来读取所有文件。那里的开销很小,因为它是未压缩的。

于 2013-01-02T22:24:03.413 回答
1

听起来您正在尝试编写一个尽可能快地下载尽可能多内容的应用程序。您应该知道,当您这样做时,人们很可能会注意到,因为这会占用大量带宽和其他资源。

由于这是 Windows/NTFS,因此您需要记住一些事项: - 一个文件夹中的文件不要超过 2k。- 尽可能使用异步/缓冲写入。- 分布在尽可能多的磁盘上以获得最佳 I/O 性能。

没有提到但有些重要的一件事是文件大小。由于看起来您正在获取 JPEG,因此我将假设平均文件大小约为 50k。

我最近使用 .Net 4.0 用无尽的 ~1KB 文本文件流做了类似的事情,并且能够使本地网络上的 100mbit 网络控制器饱和。我使用 TaskFactory 生成 HttpWebRequest 线程以将数据下载到内存流。我将它们缓冲在内存中,因此我不必将它们写入磁盘。我推荐的基本方法是类似的——分离每个发出请求的线程,获取响应流,并将其写入磁盘。最难的部分是生成顺序文件夹和文件名。您希望尽快完成此操作,使其成为线程安全的,并在内存中进行簿记,以避免因对目录内容的不必要调用而撞击磁盘。

我不会担心尝试对您的写入进行排序。有足够多的 OS/NTFS 层会尝试为您执行此操作。您应该立即使某些管道饱和。

于 2013-01-03T08:09:22.603 回答
1

为了有效地做到这一点,我会多线程你的应用程序(c++)。

您的应用程序的主线程将发出这些网络请求并将它们推送到 std::list 的后面。这就是您的主应用程序线程将要做的所有事情。

产生(并保持运行,不要重复产生)一个 pthread(我首选的线程方法,即使在 Windows 上......)并将其设置为在 while 循环中检查相同的 std::list。在循环中,确保检查列表的大小,如果有要处理的事情,将最前面的项目从列表中弹出(这些可以在不同的线程中完成,而不需要互斥锁......大多数时候。 ..) 并将其写入磁盘。

这将允许您在内存中对响应进行排队,同时将文件异步保存到磁盘。如果您的服务器真的如您所说的那样快,那么您可能会耗尽内存。然后,如果要处理的项目数量超过某个阈值,我将实施一些“等待”,但这只会比串行执行好一点。

“提高”速度的真正方法是让许多工作线程(每个都有自己的 std::list 和“智能”推送到具有最少项目的列表或一个 std::list 与互斥锁共享)处理文件。如果你有一台带有多个硬盘的多核机器,这将大大提高将这些文件保存到磁盘的速度。


另一种解决方案是将文件的保存分流到许多不同的计算机上(如果当前计算机上的磁盘数量限制了写入)。通过使用诸如 ZMQ/0MQ 之类的消息传递系统,您将能够非常轻松地将文件保存到不同的系统(以 PULL 方式设置),并且可以访问比当前更多的硬盘驱动器一台机器。使用 ZMQ 使得循环式消息传递变得微不足道,因为内置了扇出架构,并且实际上只需几分钟即可实现。


另一个解决方案是创建一个 ramdisk(在 linux 上很容易在本地完成,对于 windows ......我用过这个)。这将允许您使用任意数量的编写器并行写入文件,而不会出现问题。然后,您需要确保在重新启动之前将这些文件复制到真实的存储位置,否则您会丢失文件。但是在运行过程中,您可以实时存储文件而不会出现问题。

于 2013-01-02T21:53:23.367 回答