2016-02-03 3 views
1

StringIO имеет следующие ноты в своем коде:Реальные файловые объекты медленнее, чем StringIO и cStringIO?

Notes: 
- Using a real file is often faster (but less convenient). 
- There's also a much faster implementation in C, called cStringIO, but 
    it's not subclassable. 

«Настоящий файл часто быстрее» линия казалась очень странной для меня: как можно писать на диск бить запись в память? Я попробовал профилировать эти разные случаи и получил результаты, которые противоречат этим документам, а также ответ на вопрос this question. This other question действительно объясняет, почему cStringIO медленнее при некоторых обстоятельствах, хотя я не собираюсь здесь конкатенироваться. Тест записывает заданный объем данных в файл, затем ищет начало и считывает его обратно. В «новых» тестах каждый раз я создавал новый объект, а на «тех же» я усекаю и повторно использую один и тот же объект для каждого повторения, чтобы исключить этот источник накладных расходов. Эти накладные расходы имели значение для использования tempfiles с небольшими размерами данных, но не большими.

Код here.

Using 1000 passes with size 1.0KiB 
New StringIO: 0.0026 0.0025 0.0034 
Same StringIO: 0.0026 0.0023 0.0030 
New cStringIO: 0.0009 0.0010 0.0008 
Same cStringIO: 0.0009 0.0009 0.0009 
New tempfile: 0.0679 0.0554 0.0542 
Same tempfile: 0.0069 0.0064 0.0070 
============================================================== 
Using 1000 passes with size 100.0KiB 
New StringIO: 0.0093 0.0099 0.0108 
Same StringIO: 0.0109 0.0090 0.0086 
New cStringIO: 0.0130 0.0139 0.0120 
Same cStringIO: 0.0118 0.0115 0.0124 
New tempfile: 0.1006 0.0905 0.0899 
Same tempfile: 0.0573 0.0526 0.0523 
============================================================== 
Using 1000 passes with size 1.0MiB 
New StringIO: 0.0727 0.0700 0.0717 
Same StringIO: 0.0740 0.0735 0.0712 
New cStringIO: 0.1484 0.1399 0.1470 
Same cStringIO: 0.1493 0.1393 0.1465 
New tempfile: 0.6576 0.6750 0.6821 
Same tempfile: 0.5951 0.5870 0.5678 
============================================================== 
Using 1000 passes with size 10.0MiB 
New StringIO: 1.0965 1.1129 1.1079 
Same StringIO: 1.1206 1.2979 1.1932 
New cStringIO: 2.2532 2.2162 2.2482 
Same cStringIO: 2.2624 2.2225 2.2377 
New tempfile: 6.8350 6.7924 6.8481 
Same tempfile: 6.8424 7.8114 7.8404 
============================================================== 

StringIO Две реализации были довольно сопоставимы, хотя cStringIO существенно замедлилась для больших объемов данных. Но tempfile.TemporaryFile всегда занимал в 3 раза длиннее StringIO.

+0

Я не верю, что вы сравниваете правильные вещи здесь. Эти ответы говорят о вашей основной файловой оболочке Python - 'file' - не' tempfile.TemporaryFile'. –

+0

Возможно, потому что файл IO обе оптимизирован ОС и проходит через кеш-память, которая, скорее всего, будет быстрее в некоторых распространенных случаях, чем то, что делает модуль Python в фоновом режиме. – dtanders

+0

@ Two-BitAlchemist Я бы не ожидал, что 'TemporaryFile' будет сильно отличаться от' file' для чтения и записи. И глядя на 'tempfile',' TemporaryFile' на самом деле является функцией, которая возвращает 'file's, по крайней мере, на POSIX (это то, что я использовал). Любые накладные расходы из-за различий в создании должны быть учтены в случаях «того же tempfile». –

ответ

3

Все зависит от того, что означает «часто». StringIO реализуется путем хранения ваших записей в списке и последующего объединения списка с строкой при чтении. Ваш тестовый пример - серия записей, за которыми следует чтение - это лучший сценарий. Если я подберу тестовый пример, чтобы сделать 50 случайных операций записи/чтения в файл, то cStringIO имеет тенденцию выигрывать с файловой системой на втором месте.

Комментарий, похоже, отражает предвзятость системного программиста, чтобы библиотеки c и операционная система выполняли файловую систему, потому что трудно угадать в общем смысле, что лучше всего подходит при любых условиях.

def write_and_read_test_data(flo): 
    fsize = len(closure['test_data']) 
    flo.write(closure['test_data']) 
    for _ in range(50): 
     flo.seek(random.randint(0, fsize-1)) 
     flo.write('x') 
     flo.read(1) 
    flo.seek(0) 
    closure['output'] = flo.read() 

Испытания 10meg дело заняло больше времени, чем моя продолжительность концентрации внимания ...

Using 1000 passes with size 1.0KiB 
New StringIO: 0.9551 0.9467 0.9366 
Same StringIO: 0.9252 0.9228 0.9207 
New cStringIO: 0.3274 0.3280 0.3251 
Same cStringIO: 0.3182 0.3231 0.3280 
New tempfile: 1.1833 1.1853 1.1650 
Same tempfile: 0.9563 0.9414 0.9504 
============================================================== 
Using 1000 passes with size 100.0KiB 
New StringIO: 5.6253 5.6589 5.6025 
Same StringIO: 5.5799 5.5608 5.5589 
New cStringIO: 0.4157 0.4133 0.4140 
Same cStringIO: 0.4078 0.4076 0.4088 
New tempfile: 2.0420 2.0391 2.0408 
Same tempfile: 1.5722 1.5749 1.5693 
============================================================== 
Using 1000 passes with size 1.0MiB 
New StringIO: 105.2350 106.3904 107.5411 
Same StringIO: 108.3744 109.4510 105.6012 
New cStringIO: 2.4698 2.4781 2.4165 
Same cStringIO: 2.4699 2.4600 2.4451 
New tempfile: 6.6086 6.5783 6.5916 
Same tempfile: 6.1420 6.1614 6.1366 
+0

D'oh! Случайный доступ должен вызывать 'StringIO' для копирования огромных объемов данных, поскольку он поддерживается неизменяемыми строками. Интересно: другой ответ утверждает, что это связано с интерпретируемой природой Python, но, похоже, это на самом деле не преступник. Я просто добавил '_pyio.BytesIO' к тесту: он реализован в Python, например' StringIO', но использует изменчивые байты. Это заняло в два раза больше, чем 'cStringIO', и все равно проигрывал' TemporaryFile', несмотря на то, что был интерпретирован. Думаю, я добавлю ответ об этом на другой вопрос. Благодаря! –

 Смежные вопросы

  • Нет связанных вопросов^_^