python popen阻塞_python subprocess.Popen系列问题

本文介绍了在Python中使用subprocess.Popen执行命令时遇到的阻塞问题,特别是当命令包含长时间运行的任务如`ping`时。通过设置超时回调函数,关闭管道并kill子进程来解决阻塞,同时探讨了使用`preexec_fn=os.setsid`创建独立进程组以便于在超时时终止所有相关进程。此外,讨论了避免阻塞的其他方法,如重定向输出到文件,以及使用`timeout`命令与`subprocess`结合实现超时控制。
摘要由CSDN通过智能技术生成

最近在项目中遇到一个需求,前端发来一个命令,这个命令是去执行传递过来的一个脚本(shell 或者python),并返回脚本的标准输出和标准出错,如果执行超过设定时间还没结束就超时,然后终止脚本的执行。实现这个功能,自然而然先想到的是subprocess这个库了。

因此,在后端的一个脚本中调用python的subprocess去执行传递过来的脚本,通常情况下subprocess都能运行的很好,完成脚本的执行并返回。最初的实现代码如下:

run_cmd.py

#!/usr/bin/python

# -*- coding: utf-8 -*-

import subprocess

from threading import Timer

import os

class test(object):

def __init__(self):

self.stdout = []

self.stderr = []

self.timeout = 10

self.is_timeout = False

pass

def timeout_callback(self, p):

print 'exe time out call back'

print p.pid

try:

p.kill()

except Exception as error:

print error

def run(self):

cmd = ['bash', '/home/XXXX/test.sh']

p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

my_timer = Timer(self.timeout, self.timeout_callback, [p])

my_timer.start()

try:

print "start to count timeout; timeout set to be %d \n" % (self.timeout,)

stdout, stderr = p.communicate()

exit_code = p.returncode

print exit_code

print type(stdout), type(stderr)

print stdout

print stderr

finally:

my_timer.cancel()

但是偶然间测试一个shell脚本,这个shell脚本中有一行ping www.baidu.com &,shell脚本如下:

test.sh

#!/bin/bash

ping www.baidu.com (&) #加不加&都没区别

echo $$

python(父进程)用subprocess.Popen新建一个进程(子进程)去开启一个shell, shell新开一个子进程(孙进程)去执行ping www.baidu.com的命令。由于孙进程ping www.baidu.com一直在执行,就类似于一个daemon程序,一直在运行。在超时时间后,父进程杀掉了shell子进程,但是父进程阻塞在了p.communicate函数了,是阻塞在了调用wait()函数之前,感兴趣的朋友可以看一下源码_communicate函数,linux系统重点看_communicate_with_poll和_communicate_with_select函数,你会发现是阻塞在了while循环里

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值