当在一个脚本中我想使用一个 .pyd 库但通常我想使用同一 .pyd 的另一个版本时,我有这样的用例。
为了实现此目的,我在 python 脚本启动时切换 .pyd 文件,然后 import lib 导入正确的版本。
在 python 脚本的末尾(使用 atexit),我附加了可能会切换库的脚本。问题是,如果 .pyd 被某个进程(当前的 python 实例)使用并且无法卸载(我发现不可能在运行时卸载已加载的 .dll 或 .pyd),则无法更改 .pyd。所以我需要杀死 python.exe 然后运行我的脚本。
当我杀死 python.exe 时,它似乎终止了os.system
我一开始就尝试过,但它永远不会运行将执行库切换的 .bat 文件。我正在努力解决这个问题。长话短说 - 我想终止 python 进程并运行一些代码。
示例代码如下 - 它永远不会将进程 ID 打印到
test_my_case.txt
。如果我删除
&& timeout 3
它工作得很好 - 所以我认为问题是
subprocess.call
进程被杀死,因为 python 进程被杀死,并且如果在回显之前有任何延迟,它就无法打印。我尝试过的 -
os.startfile
、
os.system
、
subprocess.Popen
、
subprocess.call
。
import os
import subprocess
import atexit
# never prints PID to the test_my_case.txt
def switch_library():
command = f"taskkill /F /PID {os.getpid()} && timeout 3 && echo {os.getpid()} > test_my_case.txt"
subprocess.run(command, shell=True)
atexit.register(switch_library)
exit()
[schtasks][1]
来完成此操作,但当我希望脚本在计划后不久执行时,它不允许设置以秒为单位的启动时间,因此我转向 Powershell 脚本...
import os
import sys
import tempfile
import subprocess
import atexit
from pathlib import Path
@atexit.register
def switch_library():
temp_folder = Path(tempfile.gettempdir())
pid = os.getpid()
def write_to_file(filepath, string):
with open(filepath, "w") as fi:
fi.write(string)
cmd_script = f"taskkill /F /PID {pid} & timeout 3 & echo {pid} > %~dp0./test_my_case.txt"
batch_file = temp_folder / "terminator.bat"
write_to_file(batch_file, cmd_script)
ps_script = f"""Unregister-ScheduledTask -TaskName "library_switch" -Confirm:$false
$taskTrigger = New-ScheduledTaskTrigger -Once -At (Get-Date).AddSeconds(1)
$taskAction = New-ScheduledTaskAction -Execute "{batch_file.as_posix()}"
Register-ScheduledTask 'library_switch' -Action $taskAction -Trigger $taskTrigger
"""
ps_script_file = temp_folder / "terminator.ps1"
write_to_file(ps_script_file, ps_script)
# requires: Set-ExecutionPolicy RemoteSigned
show_ps_output = False
stdout = sys.stdout if show_ps_output else subprocess.DEVNULL
p = subprocess.Popen(["powershell.exe", ps_script], stdout=stdout)
p.communicate()