我有一个单元测试,它调用一个外部程序并进行一些测试。在那之后,外部进程被杀死,测试将尝试清理外部程序创建的文件。但是,如果我只是在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有两个文件。一个简单地锁定日志文件的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)
答案 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读取数据,直到到达文件末尾。 等待进程终止。