S1riyS
@S1riyS

Почему subprocess.Popen.communicate возвращает результат команды time (Linux) как ошибку?

Вопрос состоит из нескольких частей:
1) Для запуска Docker образов из python я решил использовать библиотеку subprocess.
main.py:
import platform

from subprocess import call, Popen, PIPE


class Docker:
    def __init__(self):
        self._docker_compose_up()
        self.current_path_command = self._get_current_path_command()
        self.runner_images = {
            'cpp': 'compilers_cpp_runner',
            'python': 'compilers_python_runner'
        }

    @staticmethod
    def _get_current_path_command():
        if platform.system() == 'Windows':
            return '%CD%'
        return '$(pwd)'

    @staticmethod
    def _docker_compose_up():
        call('docker-compose up -d --build --force-recreate --renew-anon-volumes')

    @staticmethod
    def docker_compose_down():
        call('docker-compose down')

    def run_code(self, filename, language):
        image = self.runner_images[language]
        command = f'docker run -i -v {self.current_path_command}/temp:/temp --env FILENAME={filename} {image}'

        result = Popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE, shell=True, encoding='utf-8')
        output, error = result.communicate(input='12 2')

        return {'output': output, 'error': error}


docker = Docker()
print(docker.run_code('hello_world', 'cpp'))
print(docker.run_code('hello_world', 'python'))
docker.docker_compose_down()

Пояснение к коду:
Сначала я запускаю docker-compose.yml, который лежит в той же директории, что и python файл.
Потом определяю команду для получения текущего местоположения в файловой системе (Если ОС - Windows, то это %CD%, если что-то другое, то $(pwd))
Потом запускаю образ (метод run_code), передавая туда имя файла и язык.

Dockerfile для python:
FROM python
ARG FILENAME_ARG
ENV FILENAME = $FILENAME_ARG
CMD export TIMEFORMAT='%3R'
CMD bash -c "time python temp/${FILENAME}.py"


В результате выполнения функции я получаю словарь с ключами output и error:
{'output': '10\n', 'error': '\nreal\t0m0.071s\nuser\t0m0.053s\nsys\t0m0.011s\n'}


Отформатированный вывод:
real	0m0.072s
user	0m0.061s
sys	0m0.001s


Почему время выполнения улетает в error, а не в output?

2) Нормально ли я реализовываю это, или существуют какие-то другие способы сделать все правильнее и красивее?
3) Как сделать так, чтобы выводилось только real время в секундах (команда CMD export TIMEFORMAT='%3R' не сработала)
  • Вопрос задан
  • 160 просмотров
Решения вопроса 1
вот два примера докерфайла
передающих строку форматирования команде time через опцию и окружение
и перенаправляющие stderr в stdout
FROM python:3.8.2-alpine
ARG FILENAME_ARG
ENV FILENAME $FILENAME_ARG
# time on alpine does not recognize a long --format argument
CMD time -f '%U' python temp/${FILENAME} 2>&1

FROM python:3.8.2-alpine
ARG FILENAME_ARG
ENV FILENAME $FILENAME_ARG
ENV TIME '%u'
CMD time python temp/${FILENAME} 2>&1

а почитать какие форматы поддериживаются проще всего через man time

https://man7.org/linux/man-pages/man1/time.1.html

TIME(1)                     General Commands Manual                    TIME(1)

NAME
       time - run programs and summarize system resource usage


 %U     Total number of CPU-seconds that the process spent in user
              mode.
...
%R     Number of minor, or recoverable, page faults.

не думаю что вам нужет был %R
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы