自带的 print 函数居然会报错?(下)

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 最近用 Python 写了几个简单的脚本来处理一些数据,因为只是简单功能所以我就直接使用 print 来打印日志。

解决办法


既然知道了问题原因,那解决起来就比较简单了,主要有以下几个方案:


  1. 使用 read() 函数读取管道中的数据,全部读取之后再关闭。


  1. 如果不需要子进程中的输出时,也可以将 command 的标准输出重定向到 /dev/null


  1. 也可以使用 Python3subprocess.Popen 模块来运行。


这里使用第一种方案进行演示:


import os
import time
if __name__ == '__main__':
    start = int(time.time())
    cmd = 'python test.py'
    with os.popen(cmd) as p:
        print p.read()
    end = int(time.time())
    print 'end****{}s'.format(end-start)


网络异常,图片无法展示
|


运行 task.py 之后不会再抛异常,同时也将 command 的输出打印出来。


线上修复时我没有采用这个方案,为了方便查看日志,还是使用标准的日志框架将日志输出到了 es 中,方便统一在 kibana 中进行查看。


由于日志框架并没有使用到管道,所以自然也不会有这个问题。


更多内容


问题虽然是解决了,其中还是涉及到了一些咱们平时不太注意的知识点,这次我们就来一起回顾一下。


首先是父子进程的内容,这个在 c/c++/python 中比较常见,在 Java/golang 中直接使用多线程、协程会更多一些。


比如这次提到的 Python 中的 os.popen() 就是创建了一个子进程,既然是子进程那肯定是需要和父进程进行通信才能达到协同工作的目的。


很容易想到,父子进程之间可以通过上文提到的管道(匿名管道)来进行通信。


还是以刚才的 Python 程序为例,当运行 task.py 后会生成两个进程:


网络异常,图片无法展示
|


分别进入这两个程序的 /proc/pid/fd 目录可以看到这两个进程所打开的文件描述符。


父进程:


网络异常,图片无法展示
|


子进程:


网络异常,图片无法展示
|


可以看到子进程的标准输出与父进程关联,也就是 popen() 所返回的那个文件描述符。


这里的 0 1 2 分别对应一个进程的stdin(标准输入)/stdout(标准输出)/stderr(标准错误)。


还有一点需要注意的是,当我们在父进程中打开的文件描述符,子进程也会继承过去;

比如在 task.py 中新增一段代码:


x = open("1.txt", "w")


之后查看文件描述符时会发现父子进程都会有这个文件:


网络异常,图片无法展示
|


但相反的,子进程中打开的文件父进程是不会有的,这个应该很容易理解。


总结


一些基础知识在排查一些诡异问题时显得尤为重要,比如本次涉及到的父子进程的管道通信,最后来总结一下:


  1. os.popen() 函数是异步执行的,如果需要拿到子进程的输出,需要自行调用 read() 函数。


  1. 父子进程是通过匿名管道进行通信的,当读取端关闭时,写入端输出到达管道最大缓存时会收到 SIGPIPE 信号,从而抛出 Broken pipe 异常。


  1. 子进程会继承父进程的文件描述符。


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
7月前
|
IDE Java Shell
聊聊 print 的前世今生
聊聊 print 的前世今生
71 1
|
1月前
|
JavaScript 前端开发 Java
print_numbers_up_to 函数介绍
【10月更文挑战第20天】
53 12
|
3月前
|
Rust 编译器 C++
使用 def、cdef、cpdef 创建函数
使用 def、cdef、cpdef 创建函数
49 0
|
3月前
让function_graph输出返回值
让function_graph输出返回值
让function_graph输出返回值
|
5月前
|
语音技术 Python
语音识别,continue和break的使用,循环综合案例,完成发工资案例,函数的初体验,len()是内置好的函数,def 函数名 def xxx(),函数的定义 def xxx() ,调用函数
语音识别,continue和break的使用,循环综合案例,完成发工资案例,函数的初体验,len()是内置好的函数,def 函数名 def xxx(),函数的定义 def xxx() ,调用函数
|
6月前
|
JSON 数据格式 索引
Python内置函数如`print()`输出信息,`len()`计算长度
【6月更文挑战第23天】Python内置函数如`print()`输出信息,`len()`计算长度,`type()`识别类型,`range()`生成序列,`sum()`求和,`min()`和`max()`找极值,`abs()`取绝对值,`round()`四舍五入,`sorted()`排序,`zip()`和`enumerate()`组合及遍历,`map()`和`filter()`应用函数。标准库如`os`用于操作系统交互,`sys`处理解释器信息,`math`提供数学运算,`re`支持正则表达式,`json`处理JSON数据。学习这些能提升编程效率。
68 5
echo 、print 及print_r() 、var_dump()的区别
echo 、print 及print_r() 、var_dump()的区别
94 0
|
Python
一日一技:print函数也能写文件
一日一技:print函数也能写文件
163 0
print 方法输出
print 方法输出
131 0
print 方法输出