0

progressbar 모듈에 매우 만족하며 StdOut 리디렉션 기능을 많이 사용합니다. 최근에, (pathos) multiprocessing을 사용하기 시작했지만,이 두 가지를 결합하여 작동시킬 수는 없습니다.파이썬은 다중 프로세스를 사용하여 stdout (progressbar)을 리디렉션합니다.

또한 키보드 인터럽트에 몇 가지 문제가있어서 a bug in Python2이 원인이라고 읽었습니다. 이 문제와 관련이있는 경우를 대비하여 내가 사용하는 코드를 추가했습니다.

또한지도 기능을 사용하여 많은 문제를 해결할 수 있다는 것을 알게되었습니다. 중간 결과를 CSV 파일에 쓰고 물론 진행률 표시 줄을 표시하고 싶기 때문에 imap을 사용하고 있습니다.

저는 StdOut과 함께 놀았으며 인터넷에서 몇 가지 제안을 시도했습니다. 그러나 나는 항상 두 가지 바람직하지 않은 상황에 처하게됩니다.

다음 중 하나를

  1. STDOUT 리디렉션하지 도착하고 진행 막대는 각 인쇄 문 다음에 반복됩니다.
  2. StdOut가 리디렉션되지만 작업자의 출력은 표시되지 않습니다.

    import time, signal, multiprocessing 
    import progressbar 
    
    
    def do_work(number): 
        if not number % 500: 
         print 'Special log occasion ...' 
        time.sleep(0.1) 
    
    def example(redirect_stdout): 
        workers = multiprocessing.cpu_count() 
        num_tasks = 1000 
        pbar = progressbar.ProgressBar(widgets=[progressbar.Bar()], max_value=num_tasks, redirect_stdout=redirect_stdout) 
        pbar.start() 
    
        # Start a with SIGINT turned of, so that workers can be interrupted 
        original_sigint_handler = signal.signal(signal.SIGINT, signal.SIG_IGN) 
        pool = multiprocessing.Pool(processes=workers) 
        signal.signal(signal.SIGINT, original_sigint_handler) 
    
    
        for i, _ in enumerate(pool.imap(do_work, xrange(num_tasks)), 1): 
         pbar.update(i) 
    
        pool.close() 
        pool.join() 
        pbar.finish() 
    
    print "Case1: Progressbar without redirecting output:" 
    example(False) 
    print "\nCase1: Progressbar without redirecting output:" 
    example(True) 
    

    출력 :

  3. 여기

내 문제 보여주는 몇 가지 장난감 코드

Case1: Progresspar without redirecing output: 
Special log occasion ... 
|######################      | 
Special log occasion ... 
|#############################################| 


Case2: Progresspar with redirecing output: 
|#############################################| 

답변

1

여러 프로세스를 사용하여 동일한 출력 스트림에 쓰기를 항상 동기화 문제 경향, 또는 더 나쁜, 덮어 쓰기/누락 된 데이터. 다행히이이 문제를 해결하기가 어렵지 않다 :

# vim: set fileencoding=utf-8 
import six 
import sys 
import time 
import signal 
import multiprocessing 
import progressbar 


def do_work(number): 
    if not number % 50: 
     print 'Special log occasion ...' 
     sys.stdout.flush() 
    time.sleep(0.1) 


class IOQueue(six.StringIO): 

    ''' 
    Very poor and simple IO wrapper which only functions for simple print 
    statements 
    ''' 

    def __init__(self, queue, *args, **kwargs): 
     six.StringIO.__init__(self, *args, **kwargs) 
     self.queue = queue 

    def write(self, value): 
     self.queue.put(value) 


def example(redirect_stdout): 
    workers = multiprocessing.cpu_count() 
    num_tasks = 1000 
    pbar = progressbar.ProgressBar(
     widgets=[progressbar.Bar()], 
     max_value=num_tasks, 
     redirect_stdout=redirect_stdout, 
    ) 
    # Start a with SIGINT turned of, so that workers can be interrupted 
    original_sigint_handler = signal.signal(signal.SIGINT, signal.SIG_IGN) 

    stdout_queue = multiprocessing.Queue() 

    def initializer(queue): 
     sys.stdout = IOQueue(queue) 

    pool = multiprocessing.Pool(
     processes=workers, initializer=initializer, initargs=[stdout_queue]) 
    signal.signal(signal.SIGINT, original_sigint_handler) 

    for i, _ in enumerate(pool.imap(do_work, xrange(num_tasks)), 1): 
     while not stdout_queue.empty(): 
      sys.stdout.write(stdout_queue.get()) 

     pbar.update(i) 

    pool.close() 
    pool.join() 
    pbar.finish() 

example(True) 

위의 코드는 모든 근로자가 진행 표시 줄을 업데이트하기 전에 정기적으로 표준 출력에 기록되는 멀티 큐에 표준 출력 데이터를 기록한다.

관련 문제