2015-06-12 2 views
-1

Рассмотрим следующую программу:Почему этот скрипт замедляется для каждого элемента с увеличением количества ввода?

#!/usr/bin/env pypy 

import json 
import cStringIO 
import sys 

def main(): 
    BUFSIZE = 10240 
    f = sys.stdin 
    decoder = json.JSONDecoder() 
    io = cStringIO.StringIO() 

    do_continue = True 
    while True: 
     read = f.read(BUFSIZE) 
     if len(read) < BUFSIZE: 
      do_continue = False 
     io.write(read) 
     try: 
      data, offset = decoder.raw_decode(io.getvalue()) 
      print(data) 
      rest = io.getvalue()[offset:] 
      if rest.startswith('\n'): 
       rest = rest[1:] 
      decoder = json.JSONDecoder() 
      io = cStringIO.StringIO() 
      io.write(rest) 
     except ValueError, e: 
      #print(e) 
      #print(repr(io.getvalue())) 
      continue 
     if not do_continue: 
      break 

if __name__ == '__main__': 
    main() 

А вот тест:

$ yes '{}' | pv | pypy parser-test.py >/dev/null 

Как вы можете видеть, следующий сценарий замедляющий при добавлении большего вклада в него. Это также происходит с cPython. Я попытался профилировать скрипт, используя mprof и cProfile, но я не нашел никакого намека на то, почему это так. Кто-нибудь знает?

+1

Почему бы * не * он становится медленнее с большим входом? – jonrsharpe

+0

Я попытался сделать его итеративным - получить объект, распечатать его и отбросить. Я бы не ожидал утечек памяти. Вы его видите? – d33tah

+0

Я не говорю об утечке памяти! Чем дольше вход, тем дольше он будет обрабатываться, если только ваш алгоритм не равен «O (1)». Или вы имеете в виду, что для увеличения длины входного сигнала требуется больше ** на предмет **? – jonrsharpe

ответ

1

Очевидно, струнные операции замедлили его. Вместо того, чтобы:

 data, offset = decoder.raw_decode(io.getvalue()) 
     print(data) 
     rest = io.getvalue()[offset:] 
     if rest.startswith('\n'): 
      rest = rest[1:] 

Это лучше сделать:

 data, offset = decoder.raw_decode(io.read()) 
     print(data) 
     rest = io.getvalue()[offset:] 
     io.truncate() 
     io.write(rest) 
     if rest.startswith('\n'): 
      io.seek(1) 
0

Возможно, вы захотите закрыть свой StringIO в конце итерации (после написания).

io.close()

Буфер памяти для StringIO освободит, когда он закрыт, но будет оставаться открытым иначе. Это объясняет, почему каждый дополнительный вход замедляет ваш скрипт.

+0

Нравится? https://gist.github.com/d33tah/09144ba0ce596a6b92ba – d33tah

+0

Несомненно, там или сразу выставляю сообщение if-else. Просто закрыв его, каждая итерация должна держать буфер достаточно свободным. – eleventhend

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