-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Расширенное тестирование (kks test 2.0) #131
Comments
Что стоит учесть в реализации
Сравнение производительности методов запуска генератораПростой генератор: # 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])) Отдельный процесс для каждого теста ( # 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()) Вызов функции в цикле. Во время выполнения функции # 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()) Такая реализация может некорректно работать в многопоточном коде (какой-то вывод из других потоков может попасть в Альтернативный вариант реализации (запуск цикла в отдельном процессе, перенаправление в pipe)Тестовый код, может содержать баги # new.py
import fcntl
import os
import sys
from signal import SIGINT
from gen import gen_input
DBG = bool(sys.argv[2]) if len(sys.argv) > 2 else False
# Probably UNIX-only
p_control_gen, p_control_main = os.pipe()
p_feedback_main, p_feedback_gen = os.pipe()
p_result_main, p_result_gen = os.pipe()
pid = os.fork()
if not pid:
os.close(p_control_main)
os.close(p_feedback_main)
os.close(p_result_main)
# possible flush of old stdout?
sys.stdin = open(p_control_gen, 'r')
sys.stdout = open(p_result_gen, 'w')
feedback = open(p_feedback_gen, 'w')
try:
while True:
test = int(input()) # Use binary?
gen_input(test)
sys.stdout.flush()
feedback.write('1')
feedback.flush()
except KeyboardInterrupt:
pass
else:
os.close(p_control_gen)
os.close(p_feedback_gen)
os.close(p_result_gen)
control = open(p_control_main, 'w')
result = p_result_main
feedback = p_feedback_main
flg = fcntl.fcntl(feedback, fcntl.F_GETFL)
fcntl.fcntl(feedback, fcntl.F_SETFL, flg | os.O_NONBLOCK)
flg = fcntl.fcntl(result, fcntl.F_GETFL)
fcntl.fcntl(result, fcntl.F_SETFL, flg | os.O_NONBLOCK)
for test in range(int(sys.argv[1])):
control.write(str(test)+'\n')
control.flush()
data = []
BUFSIZE = 4096
while True:
#chunk = result.read(BUFSIZE)
chunk = None
try:
chunk = os.read(result, BUFSIZE)
if not chunk: # EOF
break
data.append(chunk)
except BlockingIOError:
pass # empty input / sync issues?
if chunk is None or len(chunk) < BUFSIZE:
try:
chk = os.read(feedback, 1)
if chk:
break
except BlockingIOError:
pass # more data available
test_input= b''.join(data)
if DBG:
print(test_input.decode())
os.close(result)
os.close(feedback)
os.kill(pid, SIGINT)
os.wait() Сравнение: $ 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 раз. |
Идея ещё с прошлого года, но до её реализации я так и не дошёл.
Возможно, заинтересует кого-нибудь из слушателей АКОСа этого года.
Во второй половине курса было много задач, в которых использовались аргументы командной строки и/или предполагалась работа с файловой системой.
kks test
умеет генерировать только входные данные для программы (в теории, с флагом-v
генератор может изменять ФС, но это изначально не предполагалось).Есть предложение расширить функционал тестирования, чтобы можно было:
(например, создавать файлы/директории, с которыми должна работать программа, а после тестирования удалять их)
В такой реализации
gen.py
может выглядеть примерно так:The text was updated successfully, but these errors were encountered: