python即时输出

sunmengqi    2020-11-05 10:46

    最近项目中遇到一个问题,在docker中运行的程序明明已经启动,进程中也已经在RUN,但是logs中并没有任何内容。查了多遍代码也没有发现什么问题,最后发现一个很白痴的错误,码一下:
    该程序是一个定时启动的脚本程序,程序中使用的是APScheduler包实现的定时启动,并且使用supervisor管理后台运行,程序本身并没有错误,不过我偷懒使用print输出在日志文件中,这一操作导致程序正常运行但是日志中没有内容。
    当我们打印一些字符时,并不是调用print函数后就立即打印的。一般会先将字符送到缓冲区,然后再打印。这就存在一个问题,如果你想立刻看到日志,但由于缓冲区没满,不会打印。就需要采取一些手段。如每次打印后强行刷新缓冲区。
    解决方案:
* sys.stdout.flush()
python的stdout是有缓冲区的,举个例子:
    import time
        import sys
        for i in range(5):
            print i,
            #sys.stdout.flush()
            time.sleep(1)

这个程序本意是每隔一秒输出一个数字,但是如果把这句话sys.stdout.flush()注释的话,你就只能等到程序执行完毕,日志里会一次性输出0,1,2,3,4。
如果你加上sys.stdout.flush(),刷新stdout,这样就能每隔一秒输出一个数字了。
可以用在网络程序中多线程程序,多个线程后台运行,同时要能在屏幕上实时看到输出信息。
* python -u xx.py
用网上的一个程序示例来说明,python中stdout默认需要缓存后再输出到屏幕,而stderr则直接打印到屏幕
import sys
sys.stdout.write("stdout1")
sys.stderr.write("stderr1")
sys.stdout.write("stdout2")
sys.stderr.write("stderr2")
其中sys.stdout.write()和sys.stderr.write()均是向屏幕打印的语句。其实python中的print语句就是调用了sys.stdout.write(),例如在打印对象调用print obj时,事实上是调用了 sys.stdout.write(obj+'\n')。
预想的结果是:stdout1stderr1stdout2stderr2
实际的结果为:stderr1stderr2stdout1stdout2
原因是python缓存机制,虽然stderr和stdout默认都是指向屏幕的,但是stderr是无缓存的,程序往stderr输出一个字符,就会在屏幕上显示一个;而stdout是有缓存的,只有遇到换行或者积累到一定的大小,才会显示出来。这就是为什么上面的会最先显示两个stderr的原因!
- u参数的使用
有了上面的铺垫,就可以引出python 的- u参数了。python命令加上- u(unbuffered)参数后会强制其标准输出也同标准错误一样不通过缓存直接打印到屏幕。
运行结果 :stdout1stderr1stdout2stderr2
这样变成了预期的输出了。
不难看出在将python执行脚本输出到屏幕结果直接重定向到日志文件的情况下,使用- u参数,这样将标准输出的结果不经缓存直接输出到日志文件。

PS:最后,还是推荐使用logging模块——https://blog.csdn.net/pansaky/article/details/90710751



 
Last Modified: 2020-11-05 11:34
Views: 1.3K

[[total]] comments

Post your comment
  1. [[item.time]]
    [[item.user.username]] [[item.floor]]Floor
  2. Click to load more...
  3. Post your comment