Popen 通讯不起作用

问题描述 投票:0回答:1

我有一个在过去 3 个月内一直正常运行的脚本。服务器上周一宕机了,从那时起我的脚本就停止工作了。脚本挂在

coords = p.communicate()[0].split()

这是脚本的一部分:

class SelectByLatLon(GridSelector):
def __init__(self, from_lat, to_lat, from_lon, to_lon):
self.from_lat = from_lat
self.to_lat = to_lat
self.from_lon = from_lon
self.to_lon = to_lon

def get_selection(self, file):
p = subprocess.Popen(
        [
    os.path.join(module_root, 'bin/points_from_latlon.tcl'), 
    file, 
    str(self.from_lat), str(self.to_lat), str(self.from_lon), str(self.to_lon)
    ],
        stdout = subprocess.PIPE
    )
    coords = p.communicate()[0].split()
    return ZGridSelection(int(coords[0]), int(coords[1]), int(coords[2]), int(coords[3]))   

当我在另一台服务器上运行脚本时,一切正常。 我可以用其他东西代替

p.communicate()[0].split()
吗?

python subprocess popen
1个回答
1
投票

您之前可能在没有守护进程的情况下运行服务器,即您有功能性的 stdin、stdout、stderr 流。要修复此问题,您可以将子进程的流重定向到 DEVNULL:

import os
from subprocess import Popen, PIPE

DEVNULL = os.open(os.devnull, os.O_RDWR)
p = Popen(tcl_cmd, stdin=DEVNULL, stdout=PIPE, stderr=DEVNULL, close_fds=True)
os.close(DEVNULL)

即使

.communicate()

 已经退出,
tcl_cmd
也可能会等待 stdout 上的 EOF:tcl 脚本可能会生成一个继承标准流并比其父进程寿命更长的子进程。

如果您知道在

tcl_cmd
退出后不需要任何标准输出,那么当您检测到
tcl_cmd
完成时,您可以杀死整个进程树。

您可能需要

start_new_session=True
模拟才能杀死整个进程树:

import os
import signal
from threading import Timer

def kill_tree_on_exit(p):
    p.wait() # wait for tcl_cmd to exit
    os.killpg(p.pid, signal.SIGTERM)

t = Timer(0, kill_tree_on_exit, [p])
t.start()
coords = p.communicate()[0].split()
t.cancel()

参见 如何终止使用 shell=True 启动的 python 子进程

© www.soinside.com 2019 - 2024. All rights reserved.