2017-01-13 21 views
9

मैं read और seek के बीच व्यापार को समझने की कोशिश कर रहा हूं। अनियंत्रित डेटा पढ़ने के छोटे "कूद" के लिए seek के साथ इसे छोड़ने से तेज़ है।फाइल से 2, 3, 4, ... बाइट पढ़ने से एक बाइट 20x धीमा क्यों पढ़ रहा है?

अलग पढ़ने के समय/हिस्सा आकार की तलाश टिपिंग बिंदु को खोजने के लिए करते हैं, मैं एक अजीब घटना में आए: read(1), read(3), लगभग 20 गुना read(2) की तुलना में धीमी आदि इस आशय अलग पढ़ने के तरीकों, जैसे के लिए एक ही है read() और readinto()

ऐसा क्यों है?

2 x buffered 1 byte readinto bytearray 

पर्यावरण::

Python 3.5.2 |Continuum Analytics, Inc.| (default, Jul 5 2016, 11:45:57) [MSC v.1900 32 bit (Intel)] 

समय परिणाम:

Non-cachable binary data ingestion (file object blk_size = 8192): 
- 2 x buffered 0 byte readinto bytearray: 
     robust mean: 6.01 µs +/- 377 ns 
     min: 3.59 µs 
- Buffered 0 byte seek followed by 0 byte readinto: 
     robust mean: 9.31 µs +/- 506 ns 
     min: 6.16 µs 
- 2 x buffered 4 byte readinto bytearray: 
     robust mean: 14.4 µs +/- 6.82 µs 
     min: 2.57 µs 
- 2 x buffered 7 byte readinto bytearray: 
     robust mean: 14.5 µs +/- 6.76 µs 
     min: 3.08 µs 
- 2 x buffered 2 byte readinto bytearray: 
     robust mean: 14.5 µs +/- 6.77 µs 
     min: 3.08 µs 
- 2 x buffered 5 byte readinto bytearray: 
     robust mean: 14.5 µs +/- 6.76 µs 
     min: 3.08 µs 
- 2 x buffered 3 byte readinto bytearray: 
     robust mean: 14.5 µs +/- 6.73 µs 
     min: 2.57 µs 
- 2 x buffered 49 byte readinto bytearray: 
     robust mean: 14.5 µs +/- 6.72 µs 
     min: 2.57 µs 
- 2 x buffered 6 byte readinto bytearray: 
     robust mean: 14.6 µs +/- 6.76 µs 
     min: 3.08 µs 
- 2 x buffered 343 byte readinto bytearray: 
     robust mean: 15.3 µs +/- 6.43 µs 
     min: 3.08 µs 
- 2 x buffered 2401 byte readinto bytearray: 
     robust mean: 138 µs +/- 247 µs 
     min: 4.11 µs 
- Buffered 7 byte seek followed by 7 byte readinto: 
     robust mean: 278 µs +/- 333 µs 
     min: 15.4 µs 
- Buffered 3 byte seek followed by 3 byte readinto: 
     robust mean: 279 µs +/- 333 µs 
     min: 14.9 µs 
- Buffered 1 byte seek followed by 1 byte readinto: 
     robust mean: 279 µs +/- 334 µs 
     min: 15.4 µs 
- Buffered 2 byte seek followed by 2 byte readinto: 
     robust mean: 279 µs +/- 334 µs 
     min: 15.4 µs 
- Buffered 4 byte seek followed by 4 byte readinto: 
     robust mean: 279 µs +/- 334 µs 
     min: 15.4 µs 
- Buffered 49 byte seek followed by 49 byte readinto: 
     robust mean: 281 µs +/- 336 µs 
     min: 14.9 µs 
- Buffered 6 byte seek followed by 6 byte readinto: 
     robust mean: 281 µs +/- 337 µs 
     min: 15.4 µs 
- 2 x buffered 1 byte readinto bytearray: 
     robust mean: 282 µs +/- 334 µs 
     min: 17.5 µs 
- Buffered 5 byte seek followed by 5 byte readinto: 
     robust mean: 282 µs +/- 338 µs 
     min: 15.4 µs 
- Buffered 343 byte seek followed by 343 byte readinto: 
     robust mean: 283 µs +/- 340 µs 
     min: 15.4 µs 
- Buffered 2401 byte seek followed by 2401 byte readinto: 
     robust mean: 309 µs +/- 373 µs 
     min: 15.4 µs 
- Buffered 16807 byte seek followed by 16807 byte readinto: 
     robust mean: 325 µs +/- 423 µs 
     min: 15.4 µs 
- 2 x buffered 16807 byte readinto bytearray: 
     robust mean: 457 µs +/- 558 µs 
     min: 16.9 µs 
- Buffered 117649 byte seek followed by 117649 byte readinto: 
     robust mean: 851 µs +/- 1.08 ms 
     min: 15.9 µs 
- 2 x buffered 117649 byte readinto bytearray: 
     robust mean: 1.29 ms +/- 1.63 ms 
     min: 18 µs 

तरह से की निम्न पंक्ति 2/3 के माध्यम से किए जाने का समय परिणामों में

खोजें बेंचमार्किंग कोड:

from _utils import BenchmarkResults 

from timeit import timeit, repeat 
import gc 
import os 
from contextlib import suppress 
from math import floor 
from random import randint 

### Configuration 

FILE_NAME = 'test.bin' 
r = 5000 
n = 100 

reps = 1 

chunk_sizes = list(range(7)) + [7**x for x in range(1,7)] 

results = BenchmarkResults(description = 'Non-cachable binary data ingestion') 


### Setup 

FILE_SIZE = int(100e6) 

# remove left over test file 
with suppress(FileNotFoundError): 
    os.unlink(FILE_NAME) 

# determine how large a file needs to be to not fit in memory 
gc.collect() 
try: 
    while True: 
     data = bytearray(FILE_SIZE) 
     del data 
     FILE_SIZE *= 2 
     gc.collect() 
except MemoryError: 
    FILE_SIZE *= 2 
    print('Using file with {} GB'.format(FILE_SIZE/1024**3)) 

# check enough data in file 
required_size = sum(chunk_sizes)*2*2*reps*r 
print('File size used: {} GB'.format(required_size/1024**3)) 
assert required_size <= FILE_SIZE 


# create test file 
with open(FILE_NAME, 'wb') as file: 
    buffer_size = int(10e6) 
    data = bytearray(buffer_size) 
    for i in range(int(FILE_SIZE/buffer_size)): 
     file.write(data) 

# read file once to try to force it into system cache as much as possible 
from io import DEFAULT_BUFFER_SIZE 
buffer_size = 10*DEFAULT_BUFFER_SIZE 
buffer = bytearray(buffer_size) 
with open(FILE_NAME, 'rb') as file: 
    bytes_read = True 
    while bytes_read: 
     bytes_read = file.readinto(buffer) 
    blk_size = file.raw._blksize 

results.description += ' (file object blk_size = {})'.format(blk_size) 

file = open(FILE_NAME, 'rb') 

### Benchmarks 

setup = \ 
""" 
# random seek to avoid advantageous starting position biasing results 
file.seek(randint(0, file.raw._blksize), 1) 
""" 

read_read = \ 
""" 
file.read(chunk_size) 
file.read(chunk_size) 
""" 

seek_seek = \ 
""" 
file.seek(buffer_size, 1) 
file.seek(buffer_size, 1) 
""" 

seek_read = \ 
""" 
file.seek(buffer_size, 1) 
file.read(chunk_size) 
""" 

read_read_timings = {} 
seek_seek_timings = {} 
seek_read_timings = {} 
for chunk_size in chunk_sizes: 
    read_read_timings[chunk_size] = [] 
    seek_seek_timings[chunk_size] = [] 
    seek_read_timings[chunk_size] = [] 

for j in range(r): 
    #file.seek(0) 
    for chunk_size in chunk_sizes: 
     buffer = bytearray(chunk_size) 
     read_read_timings[chunk_size].append(timeit(read_read, setup, number=reps, globals=globals())) 
     #seek_seek_timings[chunk_size].append(timeit(seek_seek, setup, number=reps, globals=globals())) 
     seek_read_timings[chunk_size].append(timeit(seek_read, setup, number=reps, globals=globals())) 

for chunk_size in chunk_sizes: 
    results['2 x buffered {} byte readinto bytearray'.format(chunk_size)] = read_read_timings[chunk_size] 
    #results['2 x buffered {} byte seek'.format(chunk_size)] = seek_seek_timings[chunk_size] 
    results['Buffered {} byte seek followed by {} byte readinto'.format(chunk_size, chunk_size)] = seek_read_timings[chunk_size] 


### Cleanup 
file.close() 
os.unlink(FILE_NAME) 

results.show() 
results.save() 

उत्तर

1

इसका कारण यह है कि आप हर एक फोन पर समारोह के लिए पूरी तरह भूमि के ऊपर का सामना कर रहे। यदि कंप्यूटर अभी भी 8-बिट थे तो यह घटना अधिक दिलचस्प होगी।

उत्तर सरल है: बड़े मूल्यों को पार करते समय आप प्रति पुनरावृत्ति प्रति बाइट्स प्रसंस्करण कर रहे हैं; शहर के दूसरी तरफ जाने के पहले शहर के एक तरफ अपने सभी कामों को संभालने की तरह; read() में जितना अधिक गुजरता है, उतना ही अधिक मूल्य जो आप एक बार में पूरा कर रहे हैं, और जितना अधिक कुशल होना चाहिए (संभावित रूप से) होना चाहिए।

+0

मुझे डर है कि यह बिल्कुल सही नहीं है। यदि यह था, तो 1 बाइट पढ़ना केवल एक समय में 2 बाइट पढ़ने से 2x धीमा होना चाहिए। उपरोक्त मामले में यह 20x धीमा था! हालांकि प्रयास के लिए धन्यवाद। मैं अभी भी इस सवाल को भूल गया था। – ARF

संबंधित मुद्दे