Open vvd170501 opened 2 years ago
gen.py
импортируемым модулем с функциями, как в примере. gen.py
. Т.е. нужно корректно обрабатывать случай, когда в gen.py нет нужных функций.
Также можно сделать опциональными все функции, кроме gen_input
, чтобы шаблон генератора оставался небольшим.gen.py
нового формата работал со всеми версиями kks (для тестов, в которых используется только stdin).
В коде из примера это решается вызовом gen_input
при запуске файла.gen_input
использует вывод в stdout. Почему так сделано:
print
в цикле вместо return ' '.join(map(str, data))
.gen.py
старого формата при необходимости легко конвертируется в новый. Весь код достаточно перенести в gen_input
.gen_input
(как в примере), придётся найти способ перехватывать вывод функции.
Возможное решение - запустить отдельный процесс, который будет по запросу вызывать gen_input
, и читать его вывод (см. пример ниже).Простой генератор:
# gen.py
import sys
import random
def gen_input(test):
random.seed(test)
print(random.randint(1, 1000))
if __name__ == '__main__':
gen_input(int(sys.argv[1]))
Отдельный процесс для каждого теста (kks test -V
запускает генератор примерно так):
# old.py
import sys
import subprocess
DBG = bool(sys.argv[2]) if len(sys.argv) > 2 else False
for test in range(int(sys.argv[1])):
p = subprocess.run(['python3', './gen.py', str(test)], capture_output=True)
if DBG:
print(p.stdout.decode())
Вызов функции в цикле. Во время выполнения функции sys.stdout
перенаправляется в буфер
# new.py
import sys
from contextlib import redirect_stdout
from io import BytesIO, TextIOWrapper
from gen import gen_input
DBG = bool(sys.argv[2]) if len(sys.argv) > 2 else False
for test in range(int(sys.argv[1])):
with redirect_stdout(TextIOWrapper(BytesIO())) as out:
gen_input(test)
out.flush()
test_input = out.buffer.getvalue()
if DBG:
print(test_input.decode())
Такая реализация может некорректно работать в многопоточном коде (какой-то вывод из других потоков может попасть в out
вместо настоящего sys.stdout
). Пока kks использует только один поток, проблем быть не должно.
Сравнение:
$ time python old.py 100
real 0m6.199s
user 0m4.387s
sys 0m1.593s
$ time python new.py 100
real 0m0.075s
user 0m0.057s
sys 0m0.017s
Результат - ускорение в ~50-80 раз.
При реальном тестировании можно рассчитывать на максимальное ускорение в ~2 раза, т.к. тестируемое решение и solve.py
всё равно перезапускаются на каждом тесте.
Идея ещё с прошлого года, но до её реализации я так и не дошёл. Возможно, заинтересует кого-нибудь из слушателей АКОСа этого года.
Во второй половине курса было много задач, в которых использовались аргументы командной строки и/или предполагалась работа с файловой системой.
kks test
умеет генерировать только входные данные для программы (в теории, с флагом-v
генератор может изменять ФС, но это изначально не предполагалось).Есть предложение расширить функционал тестирования, чтобы можно было:
В такой реализации
gen.py
может выглядеть примерно так: