Я думаю, что узкое место у вас здесь двоякое.
В зависимости от вашей ОС и контроллера диска, вызовы f.read(2)
, где f
является большим файлом, обычно эффективно буферизируются - обычно .Другими словами, ОС будет считывать один или два сектора (с секторами диска, обычно несколько килобайт) с диска в память, потому что это не намного дороже, чем чтение 2 байтов из этого файла.Дополнительные байты эффективно кэшируются в памяти и готовы к следующему вызову для чтения этого файла.Не полагайтесь на это поведение - это может быть вашим узким местом - но я думаю, что здесь есть другие проблемы.
Меня больше беспокоит однобайтовое преобразование в короткий и одиночный вызов numpy.Они не кешируются вообще.Вы можете сохранить все шорты в списке целых чисел Python и преобразовать весь список в numy, когда (и если) необходимо.Вы также можете сделать один вызов struct.unpack_from
, чтобы преобразовать все в буфере против одного короткого за раз.
Обратите внимание:
#!/usr/bin/python
import random
import os
import struct
import numpy
import ctypes
def read_wopper(filename,bytes=2,endian='>h'):
buf_size=1024*2
buf=ctypes.create_string_buffer(buf_size)
new_buf=[]
with open(filename,'rb') as f:
while True:
st=f.read(buf_size)
l=len(st)
if l==0:
break
fmt=endian[0]+str(l/bytes)+endian[1]
new_buf+=(struct.unpack_from(fmt,st))
na=numpy.array(new_buf)
return na
fn='bigintfile'
def createmyfile(filename):
bytes=165924350
endian='>h'
f=open(filename,"wb")
count=0
try:
for int in range(0,bytes/2):
# The first 32,767 values are [0,1,2..0x7FFF]
# to allow testing the read values with new_buf[value<0x7FFF]
value=count if count<0x7FFF else random.randint(-32767,32767)
count+=1
f.write(struct.pack(endian,value&0x7FFF))
except IOError:
print "file error"
finally:
f.close()
if not os.path.exists(fn):
print "creating file, don't count this..."
createmyfile(fn)
else:
read_wopper(fn)
print "Done!"
Я создал файл случайных шорт со знаком с целым числом 165 924 350 байтов (158,24 МБ), который соответствует 82 962 175 со знаком 2-байтовых шорт.С этим файлом я запустил функцию read_wopper
, описанную выше, и она запустилась:
real 0m15.846s
user 0m12.416s
sys 0m3.426s
Если вам не нужно , чтобы шорты были пустыми, эта функция запускается через 6 секунд,Все это на OS X, Python 2.6.1, 64-битная, 2.93 ГГц Core i7, 8 ГБ оперативной памяти.Если вы измените buf_size=1024*2
в read_wopper
на buf_size=2**16
, время выполнения будет:
real 0m10.810s
user 0m10.156s
sys 0m0.651s
Таким образом, я думаю, что ваша основная горлышко бутылки - это однобайтовые вызовы для распаковки, а не 2-байтовыечитает с диска.Возможно, вы захотите убедиться, что ваши файлы данных не фрагментированы, и если вы используете OS X, что ваше свободное дисковое пространство (и здесь ) не фрагментировано.
Редактировать Я разместил полный код, чтобы создать, а затем прочитать двоичный файл целых.На моем iMac я последовательно получаю <15 секунд, чтобы прочитать файл случайных целых.Создание занимает около 1:23, поскольку создание по одному короткое за раз.</p>