java采用Process.destroy无法停止子进程
問題描述
當前的應用場景是,采用java執行一個python腳本,該腳本是一個機器學習算法,在訓練中會比較耗時。在某些場景下,需要采用java的進程主動停止該python進程。采用如下思路進行該邏輯實現。
一種錯誤的實現
啟動進程
ProcessBuilder builder = new ProcessBuilder("/bin/sh", "-c", command);TaskExecutor executor = privpyClient.getTaskExecutor(requestId);builder.redirectErrorStream(true);log.info("{} enter running the code: {}", requestId, command);Process process = null;try {process = builder.start();if (Objects.nonNull(executor)) {executor.setPlainProcess(process);}log.info("{} check if the code is started {}!", requestId, process.isAlive());} catch (IOException e) {log.error("{} start the process {} failed!,error:{}", requestId, command, e);return false;}其中command就是“python3 test.py”的啟動python進程的語句。
停止進程
Field f = process.getClass().getDeclaredField("pid"); f.setAccessible(true); long pid = f.getLong(process) + 1; log.info("{} kill process pid {} start", requestId, pid); process.destroy();這里不需看細節,其實就是將對應的process對象先進行了存儲,之后在主動停止時進行了一次調用。
其實其中的pid+1已經一定程度暴露了信息,因為我們發現真正的python進程號總是與process對象拿到的差1。
例如,我們從process拿到的pid為307,然python的進程號是308
效果
執行完process.destroy()后,對應的307進程退出,但是被拉起的308號python進程仍舊在系統中好好的存在。
問題思考
1、process作為java的進程抽象類,其真正作用是在java進程中再啟動一個子的java進程;這個停止動作也只能作用到這個主進程;
2、其中的python進程比啟動的子進程大1,因此可以從這個邏輯出發,在java停止掉process時,再發送一個系統調用的停止信號。
最后實現如下
public static void killPlainProcess(Process process, String requestId) throws Exception {Field f = process.getClass().getDeclaredField("pid");f.setAccessible(true);long pid = f.getLong(process) + 1;log.info("{} kill process pid {} start", requestId, pid);killChildProcess(pid);process.destroy();log.info("{} kill process pid {} finished ", requestId, pid); }/*** mind here, the process usd for call the kill should be clear too!!** @param pidNum*/ private static void killChildProcess(long pidNum) throws Exception {String cmd = "kill -15 " + pidNum;try {Process killProcess = null;killProcess = Runtime.getRuntime().exec(cmd);killProcess.waitFor();TimeUnit.MILLISECONDS.sleep(100);killProcess.destroy();} catch (IOException | InterruptedException e) {throw e;} }注意點:在又啟動了一個process來執行kill -15信號后,需要注意將自己也執行killProcess.destroy();做好資源清理。
但是發現多次執行后,存在不穩定情況,會導致主進程掛掉。
正確拉起python進程的實現
#### 啟動進程 ProcessBuilder builder = new ProcessBuilder("Python", command); TaskExecutor executor = privpyClient.getTaskExecutor(requestId); builder.redirectErrorStream(true); log.info("{} enter running the code: {}", requestId, command); Process process = null; try {process = builder.start();if (Objects.nonNull(executor)) {executor.setPlainProcess(process);}log.info("{} check if the code is started {}!", requestId, process.isAlive()); } catch (IOException e) {log.error("{} start the process {} failed!,error:{}", requestId, command, e);return false; }其中command就是“test.py”。
總結
以上是生活随笔為你收集整理的java采用Process.destroy无法停止子进程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: druid源码学习2-DruidData
- 下一篇: 「环卫吸粪车」天河区抽化粪池抽泥浆抽污水