Хобрук: Ваш путь к мастерству в программировании

Как дождаться завершения процесса, пока файл не будет разблокирован в Windows с помощью Python?

Описание проблемы

У меня есть модульный тест, который вызывает внешнюю программу и проводит некоторое тестирование. После этого внешний процесс уничтожается, и тест пытается очистить файлы, созданные внешней программой. Однако, если я просто вызову unlink() сразу после команды kill() в Windows 10, я получу:

PermissionError: [WinError 32] The process cannot access the file because it is being used by another process: 'my.log'

Если я time.sleep(4) перед вызовом unlink() все работает как положено. 4 выбрано произвольно, в другое время тоже работает.

MCVE

Этот MCVE состоит из двух файлов. server.py, который просто блокирует файл журнала, и test_client.py, который вызывает сервер, уничтожает его и, наконец, пытается удалить файл журнала.

test_client.py

import pathlib
import subprocess
import sys
import time

# Create test folder
server_path = pathlib.Path('.')
server_path.mkdir(exist_ok=True)

server_file = pathlib.Path('server.py').resolve()

# Start server in test folder
proc = subprocess.Popen([sys.executable, str(server_file)], cwd=server_path)

time.sleep(4)

# Kill server
proc.kill()

# Activate the following line to avoid the PermissionError: [WinError 32] ...
#time.sleep(4)

# Clean up
pathlib.Path('my.log').unlink()

server.py

import time
import logging

logging.basicConfig(
    filename='my.log',
    level=logging.DEBUG)

logging.info('I just started my work')

while True:
    time.sleep(1)

Вопрос

  • Есть ли способ дождаться завершения убийства?
  • Бонус, если код не зависит от платформы

  • Это что-то с C Win32.api. kill() не работает, как вы думали, попробуйте добавить строку proc.communicate() для ожидания завершения процесса перед вызовом unlink(), тогда все должно работать. 09.08.2018
  • Действительно, добавление proc.communicate() после proc.kill() решает проблему. 09.08.2018
  • Да, это то, что я имею в виду. proc.kill() просто сделайте запрос на отмену. Нужно как-то дождаться. communicate() для этого. Посмотрим, смогу ли я найти какой-нибудь документ для этого... 09.08.2018

Ответы:


1

Правильный способ

# Kill server
proc.kill()

# Activate the following line to avoid the PermissionError: [WinError 32] ...
proc.communicate()

# Clean up
pathlib.Path('my.log').unlink()

Причина, по которой он ведет себя так, требует некоторой документации.

Как указано в официальной документации Python,

Popen.kill() Убивает ребенка. В ОС Posix функция отправляет SIGKILL дочернему элементу. В Windows kill() является псевдонимом для terminate().

Popen.terminate() Остановить дочерний элемент. В ОС Posix метод отправляет SIGTERM дочернему элементу. В Windows для остановки дочернего процесса вызывается функция Win32 API TerminateProcess().

В Windows, как указано, он вызывает TerminateProcess функция в Win32 API. При этом ясно сказано, что

TerminateProcess является асинхронным; он инициирует завершение и немедленно возвращается. Если вам нужно убедиться, что процесс завершился, вызовите функцию WaitForSingleObject с дескриптором процесса.

Следовательно, kill() — это просто «Запросить остановку». Еще не остановился. Таким образом, вам нужен метод для «ожидания» завершения процесса.

communicate() также предназначен для этой цели, как указано в документе.

Взаимодействовать с процессом: отправить данные на стандартный ввод. Чтение данных из stdout и stderr до тех пор, пока не будет достигнут конец файла. Дождитесь завершения процесса.

09.08.2018
Новые материалы

Решения DBA Metrix
DBA Metrix Solutions предоставляет удаленного администратора базы данных (DBA), который несет ответственность за внедрение, обслуживание, настройку, восстановление базы данных, а также другие..

Начало работы с Блум
Обзор и Codelab для генерации текста с помощью Bloom Оглавление Что такое Блум? Некоторые предостережения Настройка среды Скачивание предварительно обученного токенизатора и модели..

Создание кнопочного меню с использованием HTML, CSS и JavaScript
Вы будете создавать кнопочное меню, которое имеет состояние наведения, а также позволяет вам выбирать кнопку при нажатии на нее. Финальный проект можно увидеть в этом Codepen . Шаг 1..

Внедрите OAuth в свои веб-приложения для повышения безопасности
OAuth — это широко распространенный стандарт авторизации, который позволяет приложениям получать доступ к ресурсам от имени пользователя, не раскрывая его пароль. Это позволяет пользователям..

Классы в JavaScript
class является образцом java Script Object. Конструкция «class» позволяет определять классы на основе прототипов с чистым, красивым синтаксисом. // define class Human class Human {..

Как свинг-трейдеры могут использовать ИИ для больших выигрышей
По мере того как все больше и больше профессиональных трейдеров и активных розничных трейдеров узнают о возможностях, которые предоставляет искусственный интеллект и машинное обучение для улучшения..

Как построить любой стол
Я разработчик программного обеспечения. Я люблю делать вещи и всегда любил. Для меня программирование всегда было способом создавать вещи, используя только компьютер и мое воображение...