如何在Python 2.6中获得线程安全打印?

发布于 2021-01-29 15:57:02

print根据这些
文章,Python中的Python不是线程安全的。

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

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

关注者
0
被浏览
52
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    有趣的问题-
    考虑print语句中发生的所有事情,包括softspace属性的设置和检查,使其变为“线程安全”(实际上,这是指:正在打印的线程仅对另一个线程产生“对标准输出的控制”)打印一个换行符,以确保输出的每一行都来自一个线程)是一个挑战(通常简单易行的方法来实现
    实际 线程安全-将一个单独的线程委派给“独占”并处理sys.stdout,通信)通过Queue.Queue到它-并不是那么有用,因为问题
    不是 线程安全性[[即使是简单的print
    没有崩溃的风险,并且最终输出在标准输出上的字符恰好是打印出的字符]],但是对于扩展的操作范围,线程之间需要相互排斥)。

    所以,我想我做到了:

    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 == '\n':
          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'
    

    在没有此互斥保证的情况下,调用towait的目的是为了 保证 输出的混乱混合(因此请进行评论)。 通过
    包装,即上面的代码与那里的样子完全一样,以及(至少)Python 2.5及更高版本(我相信这也可以在较早的版本中运行,但是我手头并不容易检查)输出为:

    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...
    

    “串行化”效应(如上所示,线程看起来像“轮流”)是以下事实的副作用,即成为当前正在打印的线程比其他线程慢得多(所有这些等待!
    -)。注释掉time.sleepin wait,输出改为

    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...
    

    即,一种更典型的“多线程输出” …,除了保证输出中的每一行完全来自一个线程。

    当然,例如,执行此操作的线程print 'ciao',
    保留标准输出的“所有权”,直到它最终执行打印而没有结尾逗号为止,而其他想要打印的线程可能会休眠一段时间(否则,如何保证每个线程都可以休眠)输出中的行来自单个线程吗?好,一种架构是将部分行累积到线程本地存储,而不是实际将它们写入标准输出,并且仅在接收到\n…时才进行写入,以便与softspace设置,我担心,但可能可行)。



知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看