如何在进程终止后等待,直到使用Python在Windows上将文件解锁为止?

时间:2018-08-09 09:23:54

标签: python subprocess kill-process

问题描述

我有一个单元测试,它调用一个外部程序并进行一些测试。在那之后,外部进程被杀死,测试将尝试清理外部程序创建的文件。但是,如果我只是在Windows 10上的unlink()命令之后直接调用kill(),则会得到:

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)

问题

  • 有没有办法等到杀戮结束?
  • 如果代码不是特定于平台的,则奖励

1 个答案:

答案 0 :(得分:2)

正确的方法是

# Kill server
proc.kill()

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

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

这种行为的原因需要一些文档。

Python Official Documentation中所述,

  

Popen.kill()   杀死孩子。在Posix OS上,该功能将SIGKILL发送给子级。在Windows上,kill()是Terminate()的别名。

     

Popen.terminate()   阻止孩子在Posix OS上,该方法将SIGTERM发送给子级。在Windows上,调用Win32 API函数TerminateProcess()来停止子级。

如上所述,在Windows中,它正在Win32 API上调用TerminateProcess function。同时,明确指出

  

TerminateProcess是异步;它启动终止并立即返回。如果需要确保进程已终止,请调用带有该进程句柄的WaitForSingleObject函数。

因此,kill()只是“要求停止”。尚未停止。因此,您需要一种“等待”过程结束的方法。

communicate()也是为此目的而设计的,如doc

所述
  

与进程交互:将数据发送到stdin。从stdout和stderr读取数据,直到到达文件末尾。 等待进程终止