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

Автор ykalchevskiy, 10 лет назад, По-русски

Привет!

Благодаря команде Codeforces, участникам теперь доступен PyPy. Он помогает решать задачи, которые CPython ("стандартный" Python) не может (например, 523D - Статистика обработки роликов). Но хотя PyPy практически полностью совместим с CPython, не всегда можно просто поменять язык в настройках и улучшить посылку. Вернемся к вышеупомянутой задаче. На момент написания данного текста я был единственным участником, сдавшим эту задачу на PyPy. На СPython решение не проходило из-за ограничений по времени. Связано это с особенностями реализации ввода/вывода в PyPy и CPython. Об этом уже упомянал hellman_. Дело в том, что чаще всего программы используют raw_input/print, которые реализованы не так эффективно в PyPy, как хотелось бы. Следует использовать sys.stdin/sys.stdout. У меня есть шаблон с таким содержанием:

def read():
    return stdin.readline().rstrip('\n')

def read_array(sep=None, maxsplit=-1):
    return read().split(sep, maxsplit)

def read_int():
    return int(read())

def read_int_array(sep=None, maxsplit=-1):
    return [int(a) for a in read_array(sep, maxsplit)]

def write(*args, **kwargs):
    sep = kwargs.get('sep', ' ')
    end = kwargs.get('end', '\n')
    stdout.write(sep.join(str(a) for a in args) + end)

def write_array(array, **kwargs):
    sep = kwargs.get('sep', ' ')
    end = kwargs.get('end', '\n')
    stdout.write(sep.join(str(a) for a in array) + end)

Изначально эти функции использовали raw_input/print :) Плюс этих функций в том, что они работают одинаково быстро и в PyPy, и в CPython. Более того, и во второй версии, и в третьей!

Второй момент состоит в том, что чем меньше отдельных выводов, тем лучше. Это может сыграть значительную роль! Сравните 2 посылки: 10293678 и 10293685. Лучше писать:

times = [...]
sys.stdout.write('\n'.join(str(t) for t im times) + '\n')
# or
write_array(times, sep='\n')

чем:

times = [...]
for t in times:
    sys.stdout.write(str(t) + '\n')
    # or
    write(t)

Конечно, в этом случае используется больше памяти, но памяти обычно хватает, чего не скажешь о времени.

Еще хотелось бы отметить одну вещь, которую также вскользь упомянули в комментариях к анонсу о PyPy. Обычно, на простых задачах CPython оказывается чуть быстрее, а на более долгих — быстрее PyPy.

Этим постом я хотел напомнить о том, что есть PyPy, который может немного увеличить Ваши шансы. Если Вам известны еще какие-нибудь способы по улучшения производительности (кроме перехода на C++ или Java :)) или что-либо полезное, напишите, пожалуйста, в комментариях. Спасибо!

UPD: подправил функцию read()

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

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

Параметры sep и end можно сделать обычными параметрами со значениями по умолчанию, а не таскаться в словарь. Читаемость кода от этого только возрастет, про скорость не знаю.

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

    Не совсем так. Обе функции (write и write_array) можно переписать таким образом в Python3. Но в Python2 код def write(*arr, sep=' ', end='\n'): не является корректным.

»
10 лет назад, # |
Rev. 2   Проголосовать: нравится +1 Проголосовать: не нравится

Код из 10295032 заходит и в CPython 3 (после корректировки синтаксиса), причем заметно быстрее: 10407760.

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

    Круто! Спасибо! Я даже и не подумал попробовать сдать на Python3: было чувство, что Python2 быстрее. Рад, что ошибался. Интересно, что этот же код на PyPy3 не укладывается в лимиты (10408688), а предыдущий, который на CPython3 чуть медленнее, укладывается, но тютелька в тютельку (10408700). На CPython3 проходит и код с input / print, но медленнее (10408866). Получается, что использовать sys.stdin / sys.stdout все-таки выгоднее, а вот вопрос с версией языка снова открыт.

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

Интересно, а если использовать из ctypes printf например?