Блог пользователя avamsi

Автор avamsi, история, 8 лет назад, По-английски

For some reason, the output is not buffered in PyPy (unlike CPython).
So, for problems where you use lots of print statements (especially in loops), unbuffered output has a significant effect on overall run-time performance.

For example, compare these 2 submissions -- 21354004, 21354013.
Both solutions are exactly the same except in the latter, stdout is replaced by a buffer and all the output stored in the buffer is written to original stdout at the end.

21354004 times out (1000ms TL) even though everything except buffering is same as 21354013.
21354013 runs in 360ms -- at least 3x faster than the unbuffered solution.

For explicit buffered output, prefix your code with following code like in 21354013

import atexit
import io
import sys

buff = io.BytesIO()
sys.stdout = buff


@atexit.register
def write():
    sys.__stdout__.write(buff.getvalue())


# code

Edited template (with unbuffered input), post hellman_'s comment

import atexit
import io
import sys

_INPUT_LINES = sys.stdin.read().splitlines()
raw_input = iter(_INPUT_LINES).next
_OUTPUT_BUFFER = io.BytesIO()
sys.stdout = _OUTPUT_BUFFER


@atexit.register
def write():
    sys.__stdout__.write(_OUTPUT_BUFFER.getvalue())


# code
  • Проголосовать: нравится
  • +36
  • Проголосовать: не нравится

»
8 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

I think this is what @numerix must be using!!

»
8 лет назад, # |
  Проголосовать: нравится +5 Проголосовать: не нравится

Nice! You can also read the whole input beforehand (if you have enough memory and the problem is not interactive):

sys.stdin = io.BytesIO(sys.stdin.read())

21381225 250ms (varies)

  • »
    »
    8 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    250ms (varies)

    Sure is faster than unbuffered approach!

    You don't need to override raw_input with lambda: sys.stdin.readline().rstrip() though, just overriding sys.stdin is enough.


    I tried

    _INPUT_LINES = sys.stdin.read().splitlines()
    raw_input = iter(_INPUT_LINES).next
    

    instead of using io.BytesIO as I thought (hoped?) avoiding additional lambda and str.rstrip overhead for every call would give a slight speed up but my solution (21383154) ending up taking (exactly!) the same time as yours. (I wonder if this has anything to do with Codeforces' Judge)


    Anyway, thanks for this! I'm updating the template to read all the input too.

    • »
      »
      »
      8 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится

      Does this works for PyPy3 also ?

      • »
        »
        »
        »
        8 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится
        import atexit
        import io
        import sys
        
        _INPUT_LINES = sys.stdin.read().splitlines()
        input = iter(_INPUT_LINES).__next__
        _OUTPUT_BUFFER = io.StringIO()
        sys.stdout = _OUTPUT_BUFFER
        
        
        @atexit.register
        def write():
            sys.__stdout__.write(_OUTPUT_BUFFER.getvalue())
        
        • »
          »
          »
          »
          »
          5 лет назад, # ^ |
            Проголосовать: нравится 0 Проголосовать: не нравится

          Can we use it for Python 3 ?

          • »
            »
            »
            »
            »
            »
            5 лет назад, # ^ |
              Проголосовать: нравится 0 Проголосовать: не нравится

            You could but CPython has buffered output by default so I doubt you'd see any significant gains (you might still see some modest gains from unbuffered input tho)