并行读取多个文件

Reading many files in parallel

本文关键字:文件 读取 并行      更新时间:2023-10-16

我在c++中有一个跨平台项目,我正在实时混合音频。我有几个独立的轨道作为输入,我从磁盘上不同的文件中读取。然后我混合这些,应用一些处理,并吐出一个缓冲与结果音频。我遇到的问题是磁盘IO速度。对于我正在执行的当前测试,我有大约10个轨道同时从磁盘读取。每个轨道是在原始PCM, 48000赫兹16位立体声。这意味着需要尽可能快地读取大量数据。我尝试过简单的读取调用以及通过Boost的内存映射文件,但问题是相同的。当文件第一次打开时,通常会导致音频中断(可能是在文件被操作系统读入缓存时)。在那之后,一切运行顺利,没有任何故障。目前,我通常每个文件使用一个线程,有时每个线程使用两个文件。通常,当每个线程有两个文件时,流就会发生延迟/中断。请注意,我并不事先知道需要播放哪些输入文件,因为这是由用户控制的。所以我的问题是如何以这样一种方式阅读这些初始块,这样我就不会拖延/分手。另外,当一个新文件被加载时,并不一定要从开头开始读取。

我有一些想法:

  1. 我们可以通过在启动时读取所有文件而忽略数据来预取文件到缓存中吗?我不能把它们都存到内存里。但是依赖操作系统的read cash的内部行为似乎很糟糕,特别是因为这是跨平台的。

  2. 我们可以使用Ogg Vorbis等格式进行压缩,将压缩数据完全加载到内存中,然后在飞行中解码吗?我认为解码10个或更多的Vorbis流可能过于CPU密集,但我还没有基准。至少通过这种方式,我们把它从一个I/O绑定的任务变成了一个CPU绑定的任务。

  3. 我们是否可以使用其他聪明的缓冲方法来使大读数据更均匀地分布?我对如何才能做到这一点知之甚少。

我在这一点上卡住了,并将感谢任何可能提高吞吐量的建议。

尝试使用事件处理进行文件加载。

这是你打开一堆文件描述符,让操作系统通知你的程序当数据可用。

最广泛使用的api来做这个"选择"(http://linux.die.net/man/2/select),但有更好的方法(poll, epoll, kqueue)。并不是所有地方都有。

有一些库可以为你抽象这些内容(libev和libevent)。

所以你这样做的方式是,一个线程打开你需要的所有文件,并在它们上设置一个'观察者'。当数据可用时,监视程序触发,并调用回调。

的优点是,你没有大量的线程等待和睡眠检查所有打开的文件描述符。如果这不起作用,那么很可能是硬件的io带宽饱和了——在这种情况下,你只需要等待。如果是这种情况,那么你需要做一些缓冲来避免口吃。

根据经验,您需要在单独的线程中执行文件IO操作以进行实时操作。当用户想要混合第二个音频文件时,您可以打开一个新线程,读取第二个音频文件的前N个字节,并将读取的数据返回到主线程。这也会导致延迟,但它不会破坏音频流。