복붙노트

[PYTHON] 파이썬 2.6에서 쓰레드 안전 프린트를 얻으려면 어떻게해야합니까?

PYTHON

파이썬 2.6에서 쓰레드 안전 프린트를 얻으려면 어떻게해야합니까?

이 기사에 따르면 Python으로 인쇄해도 스레드로부터 안전하지는 않습니다.

Python 3 work-around는 후자의 기사에서 제공됩니다.

파이썬 2.6에서 쓰레드 안전 프린트를 얻으려면 어떻게해야합니까?

해결법

  1. ==============================

    1.재미있는 문제 - softspace 속성의 설정 및 검사를 포함하여 print 문 내에서 발생하는 모든 것을 고려하여 "threadsafe"(실제로는 : 인쇄중인 스레드 만 "표준 출력 제어"를 다른 스레드로 보냄) newline을 출력 할 때 출력되는 모든 전체 라인이 단일 쓰레드로부터 오는 것이 보장되도록) 약간의 어려움이있었습니다 (실제 쓰레드 안전성에 대한 쉬운 접근법 - 별도의 쓰레드를 독점적으로 "소유"하고 핸들링 sys.stdout은 Queue.Queue를 통해 통신합니다. 문제는 스레드 안전성이 아니기 때문에 유용하지는 않습니다 [[일반 인쇄의 경우에도 충돌 위험이없고 표준 출력으로 끝나는 문자가 정확히 인쇄 된]]하지만 확장 된 작업 범위에서 스레드간에 상호 배제가 필요함).

    재미있는 문제 - softspace 속성의 설정 및 검사를 포함하여 print 문 내에서 발생하는 모든 것을 고려하여 "threadsafe"(실제로는 : 인쇄중인 스레드 만 "표준 출력 제어"를 다른 스레드로 보냄) newline을 출력 할 때 출력되는 모든 전체 라인이 단일 쓰레드로부터 오는 것이 보장되도록) 약간의 어려움이있었습니다 (실제 쓰레드 안전성에 대한 쉬운 접근법 - 별도의 쓰레드를 독점적으로 "소유"하고 핸들링 sys.stdout은 Queue.Queue를 통해 통신합니다. 문제는 스레드 안전성이 아니기 때문에 유용하지는 않습니다 [[일반 인쇄의 경우에도 충돌 위험이없고 표준 출력으로 끝나는 문자가 정확히 인쇄 된]]하지만 확장 된 작업 범위에서 스레드간에 상호 배제가 필요함).

    그래서, 내가 만든 것 같아. :

    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'
    

    대기 호출은이 상호 배제 보증이없는 경우 (주석이있는 경우) 혼돈스럽게 혼합 된 출력을 보장하기위한 것입니다. 파이썬 2.5와 그 이상 (위의 코드는 파이썬 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...
    

    "직렬화"efect (스레드가 위와 같이 "멋지게 라운드 로빈"하는 것처럼 보임)은 현재 인쇄중인 스레드가 다른 스레드보다 심각하게 느리다는 사실의 부작용입니다 (모두 대기합니다! -). 기다리는 시간을 주석으로 처리하는 대신 출력이 대신 사용됩니다.

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

    즉,보다 일반적인 "멀티 쓰레드 출력"... 출력의 각 라인이 하나의 단일 쓰레드에서만 제공된다는 보장은 제외합니다.

    물론, 'ciao'를 인쇄하는 스레드는 마침내 쉼표없이 인쇄를 수행 할 때까지 표준 출력의 "소유권"을 유지하며, 인쇄를 원하는 다른 스레드는 꽤 오래 동안 잠들 수 있습니다 (그 밖의 방법 출력의 각 줄이 단일 스레드에서 오는 것을 보장 할 수 있습니까? 한 가지 아키텍처는 부분 출력을 실제로 표준 출력에 쓰는 대신 부분 저장소를 스레드에 축적하여 \ n의 수신시에만 쓰기를 수행하는 것입니다. .. 소프트 스페이스 설정으로 적절하게 인터리빙하기 위해 섬세한, 나는 두려워하지만 아마도 가능할 것이다.)

  2. ==============================

    2.문제는 파이썬이 NEWLINE 인쇄와 객체 자체의 인쇄를 위해 별도의 opcode를 사용한다는 것입니다. 가장 쉬운 해결책은 명시 적 줄 바꿈을 사용하여 명시 적 sys.stdout.write를 사용하는 것입니다.

    문제는 파이썬이 NEWLINE 인쇄와 객체 자체의 인쇄를 위해 별도의 opcode를 사용한다는 것입니다. 가장 쉬운 해결책은 명시 적 줄 바꿈을 사용하여 명시 적 sys.stdout.write를 사용하는 것입니다.

  3. ==============================

    3.실험을 통해, 나는 다음과 같은 작품이 간단하고 내 요구에 맞는 것을 발견했다.

    실험을 통해, 나는 다음과 같은 작품이 간단하고 내 요구에 맞는 것을 발견했다.

    print "your string here\n",
    

    또는, 함수에 싸여,

    def safe_print(content):
        print "{0}\n".format(content),
    

    나의 이해는 일반 인쇄의 암시 적 개행이 실제로 다른 인쇄 작업과 경쟁 조건을 일으키는 별도의 작업에서 stdout으로 출력된다는 것입니다. 이 암시 적 newline을 추가 된 문자로 제거하고 문자열에 개행 문자를 포함 시키면이 문제를 피할 수 있습니다.

    2017 편집 :이 답변은 약간의 증기를 받기 시작하므로 설명을 원했습니다. 실제로 인쇄물을 "스레드 안전"으로 정확하게 만들지는 않습니다. 인쇄물이 서로 마이크로 초 간격으로 떨어져 있으면 출력물의 순서가 잘못되었을 수 있습니다. 그러나 이것이하는 일은 병행 스레드에서 실행되는 인쇄 명령문에서 오는 왜곡 된 출력을 방지합니다.이 질문은 대부분의 사람들이이 질문을 할 때 실제로 원하는 것입니다.

    내 뜻을 나타내는 테스트가 있습니다.

    from concurrent.futures import ThreadPoolExecutor
    
    
    def normal_print(content):
        print content
    
    def safe_print(content):
        print "{0}\n".format(content),
    
    
    with ThreadPoolExecutor(max_workers=10) as executor:
        print "Normal Print:"
        for i in range(10):
            executor.submit(normal_print, i)
    
    print "---"
    
    with ThreadPoolExecutor(max_workers=10) as executor:
        print "Safe Print:"
        for i in range(10):
            executor.submit(safe_print, i)
    

    산출:

    Normal Print:
    0
    1
    23
    
    4
    65
    
    7
     9
    8
    ----
    Safe Print:
    1
    0
    3
    2
    4
    5
    6
    7
    8
    9
    
  4. ==============================

    4.나는 더 좋은 방법이 잠금 메커니즘이 아니라면 알지 못한다. 그러나 atleast는 쉽게 보입니다. 인쇄가 정말로 스레드 안전하지 않은지 확실하지 않습니다.

    나는 더 좋은 방법이 잠금 메커니즘이 아니라면 알지 못한다. 그러나 atleast는 쉽게 보입니다. 인쇄가 정말로 스레드 안전하지 않은지 확실하지 않습니다.

    편집 : 좋아, 이제 내 자신을 테스트, 당신 말이 맞아, 당신은 정말 이상한보고 출력을 얻을 수 있습니다. 파이썬 2.7을 사용하기 때문에 미래의 수입은 필요 없습니다.

    from __future__ import print_function
    from threading import Lock
    
    print_lock = Lock()
    def save_print(*args, **kwargs):
      with print_lock:
        print (*args, **kwargs)
    
    save_print("test", "omg", sep='lol')
    
  5. from https://stackoverflow.com/questions/3029816/how-do-i-get-a-thread-safe-print-in-python-2-6 by cc-by-sa and MIT license