如何在 Python 2.6 中获得线程安全打印? [英] How do I get a thread safe print in Python 2.6?

查看:30
本文介绍了如何在 Python 2.6 中获得线程安全打印?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

print 在 Python 中不是线程安全的a href="http://bramcohen.livejournal.com/70686.html" rel="noreferrer">文章.

print in Python is not thread safe according to these articles.

后一篇文章中提供了 Python 3 解决方法.

A Python 3 work-around is offered in the latter article.

如何在 Python 2.6 中获得线程安全的print?

How do I get a thread safe print in Python 2.6?

推荐答案

有趣的问题 -- 考虑在 print 语句中发生的所有事情,包括 softspace 的设置和检查 属性,使其成为线程安全的"(意思是,实际上:一个正在打印的线程在打印换行符时只将标准输出的控制"交给另一个线程,因此输出的每一整行都保证来自单线程)是一个挑战(实际线程安全通常的简单方法——委托一个单独的线程专门拥有"和处理sys.stdout,通信通过 Queue.Queue 到它——并不是那么有用,因为问题是不是线程安全[[即使使用普通的print,也没有崩溃的风险和最终出现在标准输出上的字符正是那些被打印出来的字符]] 但是线程之间需要互斥以进行扩展操作).

Interesting problem -- considering all the things that happen within a print statement, including the setting and checking of the softspace attribute, making it "threadsafe" (meaning, actually: a thread that's printing only yields "control of standard output" to another thread when it's printing a newline, so that each entire line that's output is guaranteed to come from a single thread) was a bit of a challenge (the usual easy approach to actual thread safety -- delegating a separate thread to exclusively "own" and handle sys.stdout, communicate to it via Queue.Queue -- isn't all that useful, since the problem is not thread safety [[even with a plain print there is no risk of crashing and the characters that end up on standard output are exactly those which get printed]] but the need for mutual exclusion among threads for an extended range of operations).

所以,我想我做到了...:

So, I think I made it...:

import random
import sys
import thread
import threading
import time

def wait():
  time.sleep(random.random())
  return 'W'

def targ():
  for n in range(8):
    wait()
    print 'Thr', wait(), thread.get_ident(), wait(), 'at', wait(), n

tls = threading.local()

class ThreadSafeFile(object):
  def __init__(self, f):
    self.f = f
    self.lock = threading.RLock()
    self.nesting = 0

  def _getlock(self):
    self.lock.acquire()
    self.nesting += 1

  def _droplock(self):
    nesting = self.nesting
    self.nesting = 0
    for i in range(nesting):
      self.lock.release()

  def __getattr__(self, name):
    if name == 'softspace':
      return tls.softspace
    else:
      raise AttributeError(name)

  def __setattr__(self, name, value):
    if name == 'softspace':
      tls.softspace = value
    else:
      return object.__setattr__(self, name, value)

  def write(self, data):
    self._getlock()
    self.f.write(data)
    if data == '
':
      self._droplock()

# comment the following statement out to get guaranteed chaos;-)
sys.stdout = ThreadSafeFile(sys.stdout)

thrs = []
for i in range(8):
  thrs.append(threading.Thread(target=targ))
print 'Starting'
for t in thrs:
  t.start()
for t in thrs:
  t.join()
print 'Done'

wait 的调用旨在保证在没有这种互斥保证的情况下混乱的混合输出(评论由此而来).使用包装,即上面的代码与它看起来完全一样,并且(至少)Python 2.5 及更高版本(我相信这也可以在早期版本中运行,但我没有任何很容易检查)输出是:

The calls to wait are intended to guarantee chaotically mixed output in the absence of this mutual exclusion guarantee (whence the comment). With the wrapping, i.e., the above code exactly as it looks there, and (at least) Python 2.5 and up (I believe this may run in earlier versions, too, but I don't have any easily at hand to check) the output is:

Thr W -1340583936 W at W 0
Thr W -1340051456 W at W 0
Thr W -1338986496 W at W 0
Thr W -1341116416 W at W 0
Thr W -1337921536 W at W 0
Thr W -1341648896 W at W 0
Thr W -1338454016 W at W 0
Thr W -1339518976 W at W 0
Thr W -1340583936 W at W 1
Thr W -1340051456 W at W 1
Thr W -1338986496 W at W 1
  ...more of the same...

序列化"效应(线程看起来像上面那样很好地循环")是这样一个事实的副作用,即当前正在打印的线程比其他线程慢得多(所有那些等待!-).注释掉wait中的time.sleep,输出为

The "serialization" efect (whereby the threads appear to "nicely round-robin" as above) is a side effect of the fact that the thread that gets to be the currently-printing one is seriously slower than the others (all those waits!-). Commenting out the time.sleep in wait, the output is instead

Thr W -1341648896 W at W 0
Thr W -1341116416 W at W 0
Thr W -1341648896 W at W 1
Thr W -1340583936 W at W 0
Thr W -1340051456 W at W 0
Thr W -1341116416 W at W 1
Thr W -1341116416 W at W 2
Thr W -1338986496 W at W 0
  ...more of the same...

即更典型的多线程输出"……除了保证输出中的每一行完全来自一个线程.

i.e. a more typical "multithreaded output"... except for the guarantee that each line in the output comes entirely from one single thread.

当然,一个线程,例如,print 'ciao', 保持标准输出的所有权",直到它最终执行没有尾随的打印逗号,而其他想要打印的线程可能会休眠一段时间(否则如何保证输出中的每一行都来自单个线程?嗯,一种架构是将部分行累积到线程本地存储中,而不是实际写入它们到标准输出,并且只在收到 时才进行写入......我担心,它很微妙,可以与 softspace 设置正确交错,但可能可行).

Of course, a thread that does, e.g., print 'ciao', will keep "ownership" of standard output until it finally does perform a print without a trailing comma, and other threads wanting to print may sleep for quite a while (how else can one guarantee that each line in the output comes from a single thread? well, one architecture would be to accumulate partial lines to thread local storage instead of actually writing them to standard output, and only do the writing on receipt of the ... delicate to interleave properly with softspace settings, I fear, but probably feasible).

这篇关于如何在 Python 2.6 中获得线程安全打印?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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