返回顶部
首页 > 资讯 > 后端开发 > Python >为什么Python自带的Print函数会报错
  • 501
分享到

为什么Python自带的Print函数会报错

2023-06-15 12:06:12 501人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

本篇内容主要讲解“为什么python自带的Print函数会报错”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“为什么Python自带的Print函数会报错”吧!前言最近用 Python 写了几个简

本篇内容主要讲解“为什么python自带的Print函数会报错”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“为什么Python自带的Print函数会报错”吧!

前言

最近用 Python 写了几个简单的脚本来处理一些数据,因为只是简单功能所以我就直接使用 print 来打印日志

任务运行时偶尔会出现一些异常:

为什么Python自带的Print函数会报错

因为我在不同地方都有打印日志,导致每次报错的地方都不太一样,从而导致程序运行结果非常诡异;有时候是这段代码没有运行,下一次就可能是另外一段代码没有触发。

虽说当时有注意到 Broken pipe 这个关键异常,但没有特别在意,因为代码中也有一些发送 Http 请求的地方,一直以为是网络 io  出现了问题,压根没往 print 这个最基本的打印函数上思考??。

直到这个问题反复出现我才认真看了这个异常,定睛一看 print 不也是 IO 操作嘛,难道真的是自带的 print 函数都出问题了?

但在本地、测试环境我运行无数次也没能发现异常;于是我找运维拿到了线上的运行方式。

原来为了方便维护大家提交上来的脚本任务,运维自己有维护一个统一的脚本,在这个脚本中使用:

cmd = 'python /xxx/test.py' os.popen(cmd)

来触发任务,这也是与我在本地、开发环境的唯一区别。

popen 原理

为此我在开发环境模拟出了异常:

test.py:

import time if __name__ == '__main__':     time.sleep(20)     print '1000'*1024

task.py:

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

运行:

python task.py

等待 20s 必然会复现这个异常:

Traceback (most recent call last):   File "test.py", line 4, in <module>     print '1000'*1024 IOError: [Errno 32] Broken pipe

为什么会出现这个异常呢?

首先得了解 os.popen(command[, mode[, bufsize]]) 这个函数的运行原理。

为什么Python自带的Print函数会报错

根据官方文档的解释,该函数会执行 fork 一个子进程执行 command 这个命令,同时将子进程的标准输出通过管道连接到父进程;

也就该方法返回的文件描述符。

这里画个图能更好地理解其中的原理:

为什么Python自带的Print函数会报错

在这里的使用场景中并没有获取 popen() 的返回值,所以 command 的执行本质上是异步的;

也就是说当 task.py 执行完毕后会自动关闭读取端的管道。

为什么Python自带的Print函数会报错

如图所示,关闭之后子进程会向 pipe 中输出 print  '1000'*1024,由于这里输出的内容较多会一下子填满管道的缓冲区;

于是写入端会收到 SIGPIPE 信号,从而导致 Broken pipe 的异常。

从维基百科中我们也可以看出这个异常产生的一些条件:

为什么Python自带的Print函数会报错

其中也提到了 SIGPIPE 信号。

解决办法

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

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

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

也可以使用 python3 的 subprocess.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)

为什么Python自带的Print函数会报错

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

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

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

更多内容

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

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

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

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

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

为什么Python自带的Print函数会报错

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

父进程:

为什么Python自带的Print函数会报错

子进程:

为什么Python自带的Print函数会报错

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

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

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

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

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

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

为什么Python自带的Print函数会报错

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

总结

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

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

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

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

到此,相信大家对“为什么Python自带的Print函数会报错”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

--结束END--

本文标题: 为什么Python自带的Print函数会报错

本文链接: https://lsjlt.com/news/280163.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 为什么Python自带的Print函数会报错
    本篇内容主要讲解“为什么Python自带的Print函数会报错”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“为什么Python自带的Print函数会报错”吧!前言最近用 Python 写了几个简...
    99+
    2023-06-15
  • Python3把print改为函数的原理是什么
    本篇内容主要讲解“Python3把print改为函数的原理是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Python3把print改为函数的原理是什么”吧!原理阐述print 语句 早就被...
    99+
    2023-06-02
  • Python函数为什么会默认返回None
    本篇内容主要讲解“Python函数为什么会默认返回None”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Python函数为什么会默认返回None”吧!在正式开始之前,我们就用之前讨论过的 pas...
    99+
    2023-06-16
  • 为什么会报错 malloc(): invalid size (unsorted)?
    问题:为什么会报错 malloc(): invalid size (unsorted) 我在https://github.com/JamesRead5737/webcrawler/blob/master/crawler.c有一个网络爬虫代码...
    99+
    2023-09-14
    android
  • python的input,print,eval函数怎么使用
    本篇内容介绍了“python的input,print,eval函数怎么使用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!input()函数i...
    99+
    2023-06-22
  • c++中print函数的用法是什么
    在C++中没有内置的print函数,但可以使用cout来输出内容到控制台。cout是C++标准库中的一个输出流对象,可以使用<...
    99+
    2024-03-01
    c++
  • 为什么会用不好Numpy的random函数
    这期内容当中小编将会给大家带来有关为什么会用不好Numpy的random函数,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。在python数据分析的学习和应用过程中,经常需要用到numpy的随机函数,由于随...
    99+
    2023-06-04
  • oracle自带split函数的作用是什么
    Oracle数据库自带的SPLIT函数并不存在。然而,可以使用其他函数来实现相似的功能。在Oracle数据库中,可以使用REGEXP...
    99+
    2023-09-12
    oracle
  • python自定义函数中的return和print使用及说明
    目录首先,先来了解一下return自定义函数时如果return后还有代码需要被执行怎么办不加return语句会有怎样的结果在自定义函数中,return和print有什么区别总结首先,...
    99+
    2023-01-04
    python自定义函数 python return python print
  • sql注入单引号为什么会报错
    sql注入单引号会报错的原因有:不符合sql语法规则,例如://一开始SQL语句是这样的:select * from users where id='1'//当你加了单引号后变成了这样:select * fro...
    99+
    2024-04-02
  • Python的print输出函数和input输入函数怎么用
    今天小编给大家分享一下Python的print输出函数和input输入函数怎么用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧...
    99+
    2023-06-29
  • mysql中COALESCE函数为什么会失效
    mysql 中 coalesce 函数失效的原因是:参数全是 null参数类型不兼容传递 null 表达式次要错误 MySQL 中 COALESCE 函数失效的原因 COALESCE ...
    99+
    2024-05-01
    mysql
  • mysql中COALESCE函数为什么会失效
    mysql 中 coalesce 函数失效的原因是:参数全是 null参数类型不兼容传递 null 表达式次要错误 MySQL 中 COALESCE 函数失效的原因 COALESCE ...
    99+
    2024-05-01
    mysql
  • navicat新建连接为什么会带有之前的数据
    navicat 连接时出现之前数据可能是因为:1. 之前连接缓存;2. 自动连接;3. 连接字符串指定了特定 schema。解决方法:清除连接缓存、禁用自动连接、编辑连接字符串或手动选择...
    99+
    2024-04-24
    navicat
  • python中print()函数的end参数和sep参数怎么用
    小编给大家分享一下python中print()函数的end参数和sep参数怎么用,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!python 2.6中,print输出内容需要使用引号。python 3.0中的print 函数...
    99+
    2023-06-15
  • python自定义函数报错未定义怎么解决
    当你调用一个自定义函数时出现 "未定义" 的错误,可能是因为以下几个原因:1. 函数没有被正确定义:确保你在调用函数之前已经正确定义...
    99+
    2023-10-10
    python
  • 为什么自定义view的wrap_content会失效
    一、问题描述 在使用自定义View时,View宽 / 高的wrap_content属性不起自身应有的作用,而且是起到与match_parent相同作用。 wrap_content与match_parent区别: wrap_content:视...
    99+
    2023-10-29
    自定义 view wrap_content
  • 为什么当函数返回一个函数时 Go 泛型会失败?
    问题内容 我刚刚开始在 go 上尝试泛型,但遇到了一种我不完全理解它失败原因的情况。 我重构了以下函数: func positivepercentageabove(above int)...
    99+
    2024-02-05
  • 为什么我的自定义错误类型会导致特定模式的错误?
    有志者,事竟成!如果你在学习Golang,那么本文《为什么我的自定义错误类型会导致特定模式的错误?》,就很适合你!文章讲解的知识点主要包括,若是你对本文感兴趣,或者是想搞懂其中某个知识点,就请你继续...
    99+
    2024-04-05
  • python中为什么没有dict函数
    python中是存在dict函数的,dict()函数的作用是用于创建一个字典。dict()函数语法:class dict(**kwarg)class dict(mapping, **kwarg)class&nb...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作