我需要从 .wav 读取 pcm 数据,一开始使用 open() 直接打开文件,然后 read() 每次读一个样本,
测试一个 5.49M 文件, 时长 29s, 的文件,读到结尾,花了 1850 ms, 如果要处理数据。
能否通过先全部读到内存来加速, BytesIO 似乎只做这个事的, 但是我不知道它把文件读到内存是一次性的还是怎样,需要多少时间,测试花的时间差不多
from io import BytesIO
import time
if __name__ == '__main__':
with open('1875.wav', 'rb') as raw_file:
①# file = raw_file # 这句是直接从文件读取的方式
②file = BytesIO(raw_file.read()) # 这句是用了 BytesIO
start_time = time.time()
buff = []
while True:
byte = file.read(1)
if byte:
buff.append(byte)
else:
break
end_time = time.time()
print(' time using: ', (end_time - start_time) * 1000, 'msec')
使用①的情况下 time using: 1862.1060848236084 msec
使用①的情况下 time using: 1743.0999279022217 msec
时间时有浮动的
所以我想知道, ByteIO 是怎样工作的, 它能达到我的目的吗?
1
raiz OP |
2
waklin 2015-10-14 16:35:01 +08:00
你用的二进制方式打开的文件,直接调用 raw_file.read()就已经将文件读入到内存中了。
# -*- coding: utf-8 -*- import time if __name__ == '__main__': with open('TenMiLines-small.csv', 'rb') as raw_file: start_time = time.time() buff = raw_file.read() for b in buff: # print repr(b) # b 就是你所说的一个样本 pass end_time = time.time() print(' time using: ', (end_time - start_time) * 1000, 'msec') |
3
waklin 2015-10-14 16:37:33 +08:00
把 open 的文件换成 1875.wav
|
4
raiz OP @waklin hey 谢谢, 我知道 raw_file.read() 是读到内存,但是注意我的 start_time = time.time() 是放在它之后的,我是想测试从 BytesIo 读取的速度与 从 raw_file 的比较。
|
5
waklin 2015-10-14 17:46:40 +08:00
1. 你的第一个帖子里提到你处理 5.49M 的文件总共花了 29m ,读到结尾,花了 1850 ms ,如果我理解的没有错,现在你想提高的是 1850ms 的时间
2. 一个 10M 的文件我用我给出的代码的 file.read()到 buff 里,然后遍历 buff 仅花了 50ms 左右,不知道你的 1850ms 是怎么回事 3. BytesIO 和 raw_file 区别 BytesIO 维护的一段内存中的数据, read 的话,仅操作内存 raw_file 相当于一个文件游标, read 的话,是从硬盘上读取 理论上访问硬盘的速度会低于访问内存的速度,但是由于现在硬盘都会有单独的缓存,读取的数据不是很大时,差别不明显。 |
6
xylophone21 2015-10-14 19:16:28 +08:00
仅看代码,第一怀疑 buff.append(byte)这句,没验证。
|
7
xylophone21 2015-10-14 19:16:56 +08:00
看错了,请忽略我上面的帖子。。
|
8
mengzhuo 2015-10-14 22:15:49 +08:00 via iPhone
mark 目测需要流式处理
|
9
WKPlus 2015-10-14 23:34:53 +08:00
我的理解 BytesIO 的用法和 StringIO 类似,是用来提供类似文件操作一样的接口来操作内存中的 bytes 和 string 的,而不是用来全部读到内存来加速的。
你原来的程序比较慢,估计是 file.read(1)引起的,每次只读一个字节干那要循环多少次? |
10
ryd994 2015-10-15 05:47:45 +08:00
差别不会太大的,操作系统有缓存
可以考虑 os.posix_fadvise ,可能会更好, POSIX_FADV_SEQUENTIAL |
11
ryanking8215 2015-10-15 09:00:16 +08:00
class io.BytesIO([initial_bytes])
A stream implementation using an in-memory bytes buffer. raw_file 是文件流,如果 open 时如果是 rb 的, buffering=-1 的,则使用内置的 chunked buffer ,这是针对你参数的结果。 从 file.read(1)上看,都是从 file 流里取 1 个字节。从效率上看, BytesIO 是内存访问, raw_file 是 buffer+Filesystem io 的结果,所以貌似慢一点。 但这都不是正确的打开方式,要效率高就要 chunk 读,减少 FS IO 和循环次数。 BytesIO 更大的意义在抽象层次上, fs 和 buffer 都能通过 file io 访问,是不是 test 的时候简单一点? 如果错误请指正,欢迎探讨。 -) |
12
raiz OP @ryanking8215 你说的几个点应该是导致两者时间接近的原因, 默认的 fs 是有 buffer 的,而我每次只读一个 字节 ,所以那个 buffer 是够用的,所以下限不再是文件系统 io 的速度,而是在内存总遍历所有字节的速度。 说到正确的打开方式, 比如说 photoshop , 打开图片,或 audition 打开一个音频文件,应该是整一个读到内存中的吧,策略是怎样的呢?
|
13
ryanking8215 2015-10-15 10:16:31 +08:00
@raiz 这要看具体应用啊,比如图片,要显示总是需要全部的数据。比如音频视频,文件很大,播放是流的方式,只需要分片取,不需要全部数据都进 memory
|
14
matthewgao 2015-10-15 13:57:15 +08:00
我和 @ryanking8215 的意见一样。
我觉得也没有必要这么做,在你的程序里通过文件流还是 ByteIO 基本上等于没有区别 如果文件很大不可能都读到内存中来,如果你内存只有 2G ,那么 4G 的电影肿么打开, swap 到死啊。。 还是根据需求吧,如果你真的文件很小,那么你索性就一次性都读进来,循环都不用 |