为什么使用线程的脚本偶尔会打印额外的行? [英] Why a script that uses threads prints extra lines occasionally?

查看:193
本文介绍了为什么使用线程的脚本偶尔会打印额外的行?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果 print s print>> sys.stderr,s 替换,则效果消失。

If print s is replaced by print >>sys.stderr, s then the effect vanishes.

import random, sys, time
import threading

lock = threading.Lock()

def echo(s):
    time.sleep(1e-3*random.random()) # instead of threading.Timer()
    with lock:
        print s

for c in 'abc':
    threading.Thread(target=echo, args=(c,)).start()



示例



Example

# Run until empty line is found:
$ while ! python example.py 2>&1|tee out|grep '^$';do echo -n .;done;cat out



输出



Output

....................
b

c
a

输出不应该包含空行,但确实如此。我知道 print 不是线程安全的,但我认为锁应该有用。

The output should not contain empty lines, but it does. I understand that print is not thread-safe, but I would've thought the lock should help.

我的机器:

$ python -mplatform
Linux-2.6.38-11-generic-x86_64-with-Ubuntu-11.04-natty

在py26,py27,pypy上打印额外的行。

Extra lines are printed on py26, py27, pypy.

py24,py25,py31,py32按预期行事(不空线路)。

py24, py25, py31, py32 behave as expected (no empty lines).

  • sys.stdout.flush() after the print doesn't solve the problem:

with lock:
    print(s)
    sys.stdout.flush()


  • 更奇怪的是普通的 sys.stdout.write函数() 不会产生带锁的空行:

  • even more strange that ordinary sys.stdout.write() doesn't produce empty lines with lock:

    with lock:
        sys.stdout.write(s)
        sys.stdout.write('\n') #NOTE: no .flush()
    


  • print 功能 按预期工作(无空行)。

  • print function works as expected (no empty lines).

    $ tox
    


    推荐答案

    看看这个stackoverflow线程:如何在Python 2.6中获得线程安全打印?。显然,打印到sout不是线程安全的。

    Take a look at this stackoverflow thread: How do I get a thread safe print in Python 2.6?. Apparently, printing to sout is not thread-safe.

    如果你打开详细线程,你可以更好地看到它:

    If you turn on verbose threading, you can see this better:

    threading.Thread(target=echo, args=(c,), verbose=True).start()
    

    我输出如下:

    MainThread: <Thread(Thread-1, initial)>.start(): starting thread
    Thread-1: <Thread(Thread-1, started 6204)>.__bootstrap(): thread started
    MainThread: <Thread(Thread-2, initial)>.start(): starting thread
    Thread-2: <Thread(Thread-2, started 3752)>.__bootstrap(): thread started
    MainThread: <Thread(Thread-3, initial)>.start(): starting thread
    Thread-3: <Thread(Thread-3, started 4412)>.__bootstrap(): thread started
    MainThread: <Thread(Thread-2, started 3752)>.join(): waiting until thread stops
    a
    b
    Thread-1: <Thread(Thread-1, started 6204)>.__bootstrap(): normal return
    Thread-2: <Thread(Thread-2, started 3752)>.__bootstrap(): normal return
    MainThread: <Thread(Thread-2, stopped 3752)>.join(): thread stopped
    MainThread: <Thread(Thread-3, started 4412)>.join(): waiting until thread stops
    Thread-3: <Thread(Thread-3, started 4412)>.__bootstrap(): normal return
    MainThread: <Thread(Thread-3, stopped 4412)>.join(): thread stopped
    c
    

    你可以看到线程3显示为完成在打印'c'字符之前。这显然不是这种情况,因此这使我假设打印到控制台不是线程安全的。

    You can see that thread 3 is shown as finishing before printing the 'c' character. This clearly cannot be the case, so this leads me to assume that printing to the console is not thread-safe.

    然而,这并不能解释为什么打印到sys.stderr似乎能正常工作。

    This, however, does not explain why printing to sys.stderr appears to work correctly.

    这篇关于为什么使用线程的脚本偶尔会打印额外的行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆