异常后stdout不刷洗

3 投票
1 回答
2416 浏览
提问于 2025-04-17 15:32

我有以下的Python代码:

import sys
import traceback
fifo_in = sys.argv[1] 
while 1: 
  try:
    exec open(fifo_in)
  except:
    traceback.print_exc()
  sys.stdout.flush()

第一个参数是通过mkfifo创建的命名管道。所以下面的代码会打印出'1':

mkfifo input
python script.py input

... in a separate terminal ...

echo "print 1" > input

很好,到目前为止一切正常。但是当我执行类似echo "foobar" > input的命令时,脚本只打印出部分的错误追踪信息。然后它会暂停,直到我发送另一个命令,输出就会变得混乱:

echo "asdf" > input # pause here and check output
echo "print 1" > input

... in output terminal ...

Traceback (most recent call last):
  File "test.py", line 8, in <module>
    exec open(fifo_in)
  File "in", line 1, in <module>
 ...PAUSES HERE...
    print 1
NameError: name 'asdf' is not defined

这是怎么回事呢?我该如何让标准输出完全刷新,为什么输出会乱序?我试过用traceback.format_exc来替代,然后手动打印出来,但结果还是一样。调用sys.stderr.flush也没有解决任何问题。我还尝试在循环中加一个暂停,看看是否有帮助,但也没有。

更新

我发现一个有趣的现象:如果我按ctrl+c,通常程序会继续运行——try/except会捕捉到KeyboardInterrupt,然后继续循环。然而,如果我在发送错误后按ctrl+c,程序就会退出,并且我会看到以下内容。感觉就像它在print_exc里面暂停了一样:

^CTraceback (most recent call last):
  File "test.py", line 10, in <module>
    traceback.print_exc()
  File "/usr/lib/python2.7/traceback.py", line 232, in print_exc
    print_exception(etype, value, tb, limit, file)
  File "/usr/lib/python2.7/traceback.py", line 125, in print_exception
    print_tb(tb, limit, file)
  File "/usr/lib/python2.7/traceback.py", line 69, in print_tb
    line = linecache.getline(filename, lineno, f.f_globals)
  File "/usr/lib/python2.7/linecache.py", line 14, in getline
    lines = getlines(filename, module_globals)
  File "/usr/lib/python2.7/linecache.py", line 40, in getlines
    return updatecache(filename, module_globals)
  File "/usr/lib/python2.7/linecache.py", line 132, in updatecache
    with open(fullname, 'rU') as fp:
KeyboardInterrupt

1 个回答

3

我觉得你应该看看Python的标准库代码模块

这个行为是因为使用了exec。exec是用来执行Python代码的,所以“print 1”会执行这段代码print 1,而“asdf”会报错,因为在这个上下文中没有这个东西。exec open(fifo_in)这个用法很奇怪,因为它本来不应该工作。而且这个循环会让CPU使用率达到100%。

更新:修正了睡眠时间 这里有一个修改过的代码版本可以试试。

import sys
import time
import traceback
fifo_in = sys.argv[1]
try:
    fp = open(fifo_in) # will block until pipe is opened for write
except IOError:
    traceback.print_exc()
except OSError:
    traceback.print_exc()

data = None
while True:
    try:
        data = fp.read()
        try:
            exec data
        except:
            traceback.print_exc()
        finally:
            time.sleep(0.1)
    except KeyboardInterrupt:
        break

撰写回答