1

Моя конечная цель - перенаправить stdout от нескольких подпроцессов к некоторым очередям и распечатать их где-нибудь (возможно, в небольшом графическом интерфейсе).Невозможно подпроцесс многопроцессорной очереди в Python 3.5

Первым шагом является подкласс Queue в объект, который ведет себя так же, как stdout. Но вот где я застрял. Подкласс многопроцессорности Queue кажется невозможным в Python v3.5.

# This is a Queue that behaves like stdout 
# Unfortunately, doesn't work in Python 3.5 :-(
class StdoutQueue(Queue): 
    def __init__(self,*args,**kwargs): 
     Queue.__init__(self,*args,**kwargs, ctx='') 

    def write(self,msg): 
     self.put(msg) 

    def flush(self): 
     sys.__stdout__.flush() 

Я нашел этот фрагмент в следующем посте (возможно, Python 3.5 еще не существует в данный момент): Python multiprocessing redirect stdout of a child process to a Tkinter Text

В Python v3.5 вы наткнуться на странных сообщениях об ошибках, когда подклассы многопроцессорных Queue класса , Я нашел два сообщения об ошибках, описывающие проблему:

https://bugs.python.org/issue21367

https://bugs.python.org/issue19895

У меня 2 вопроса:

  1. Предположим, я хочу, чтобы придерживаться Python v3.5 - идти к предыдущей версии на самом деле не вариант. Какое обходное решение можно использовать для подкласса очереди многопроцессорности?
  2. Является ли ошибка еще при обновлении до Python v3.6?

EDIT:

Существует известная проблема, когда вы пытаетесь подкласс Queue класс найден здесь:

from multiprocessing import Queue # <- known issue: you cannot subclass 
            # this Queue class, because it is 
            # not a genuine python class. 

Но должно работать:

from multiprocessing.queues import Queue # <- from this Queue class, you 
              # should be able to make a 
              # subclass. But Python 3.5 
              # refuses :-(

К сожалению, даже это не работает в Python v3.5. Вы получите следующее сообщение об ошибке:

C:\Users\..\myFolder > python myTest.py 

     Traceback (most recent call last): 
      File "myTest.py", line 49, in <module> 
       q = StdoutQueue() 
      File "myTest.py", line 22, in __init__ 
       super(StdoutQueue,self).__init__(*args,**kwargs) 
     TypeError: __init__() missing 1 required keyword-only argument: 'ctx' 

EDIT:

Спасибо Дарт Котик для решения проблемы! Вот полный код, обновленный его решением. Теперь это работает.

import sys 
import time 
import multiprocessing as mp 
import multiprocessing.queues as mpq 
from threading import Thread 
from tkinter import * 

'''-------------------------------------------------------------------''' 
'''    SUBCLASSING THE MULTIPROCESSING QUEUE    ''' 
'''                 ''' 
'''   ..and make it behave as a general stdout io    ''' 
'''-------------------------------------------------------------------''' 
# The StdoutQueue is a Queue that behaves like stdout. 
# We will subclass the Queue class from the multiprocessing package 
# and give it the typical stdout functions. 
# 
# (1) First issue 
# Subclassing multiprocessing.Queue or multiprocessing.SimpleQueue 
# will not work, because these classes are not genuine 
# python classes. 
# Therefore, you need to subclass multiprocessing.queues.Queue or 
# multiprocessing.queues.SimpleQueue . This issue is known, and is not 
# the reason for asking this question. But I mention it here, for 
# completeness. 
# 
# (2) Second issue 
# There is another problem that arises only in Python V5 (and beyond). 
# When subclassing multiprocessing.queues.Queue, you have to provide 
# a 'multiprocessing context'. Not doing that, leads to an obscure error 
# message, which is in fact the main topic of this question. Darth Kotik 
# solved it. 
# His solution is visible in this code: 
class StdoutQueue(mpq.Queue): 

    def __init__(self,*args,**kwargs): 
     ctx = mp.get_context() 
     super(StdoutQueue, self).__init__(*args, **kwargs, ctx=ctx) 

    def write(self,msg): 
     self.put(msg) 

    def flush(self): 
     sys.__stdout__.flush() 


'''-------------------------------------------------------------------''' 
'''       TEST SETUP        ''' 
'''-------------------------------------------------------------------''' 

# This function takes the text widget and a queue as inputs. 
# It functions by waiting on new data entering the queue, when it 
# finds new data it will insert it into the text widget. 
def text_catcher(text_widget,queue): 
    while True: 
     text_widget.insert(END, queue.get()) 

def test_child(q): 
    # This line only redirects stdout inside the current process 
    sys.stdout = q 
    # or sys.stdout = sys.__stdout__ if you want to print the child to the terminal 
    print('child running') 

def test_parent(q): 
    # Again this only redirects inside the current (main) process 
    # commenting this like out will cause only the child to write to the widget 
    sys.stdout = q 
    print('parent running') 
    time.sleep(0.5) 
    mp.Process(target=test_child,args=(q,)).start() 

if __name__ == '__main__': 
    gui_root = Tk() 
    gui_txt = Text(gui_root) 
    gui_txt.pack() 
    q = StdoutQueue() 
    gui_btn = Button(gui_root, text='Test', command=lambda:test_parent(q),) 
    gui_btn.pack() 

    # Instantiate and start the text monitor 
    monitor = Thread(target=text_catcher,args=(gui_txt,q)) 
    monitor.daemon = True 
    monitor.start() 

    gui_root.mainloop() 
+0

Похож на ту же проблему, http://stackoverflow.com/questions/24941359/ctx-parameter-in-multiprocessing-queue –

+0

Привет @BiRico, большое вам спасибо. К сожалению, это не та же проблема. Проблема, описанная в этой статье, заключается в создании экземпляра объекта Queue. Проблема очереди подклассов не упоминается и не объясняется. –

+0

Мне удалось создать подкласс в Python 3.5.2, но пока не могу завершить очередь. –

ответ

3
>>> import multiprocessing 
>>> type(multiprocessing.Queue) 
<class 'method'> 
AttributeError: module 'multiprocessing' has no attribute 'queues' 
>>> import multiprocessing.queues 
>>> type(multiprocessing.queues.Queue) 
<class 'type'> 

Так как вы можете видеть multiprocessing.Queue только метод конструктора для multiprocessing.queues.Queue класса. Если вы хотите, чтобы сделать класс ребенка просто class MyQueue(multiprocessing.queues.Queue)

Вы можете увидеть источник этого метода here

EDIT: Хорошо. Теперь у меня есть твоя проблема. Как вы можете видеть по ссылке выше, multiprocessing.Queue передает ctx аргумент в очередь.Поэтому мне удалось заставить его работать, сделав это самостоятельно в методе __init__. Я не полностью понимаю, где BaseContext объект должен получить атрибут _name, поэтому я передал его вручную.

def __init__(self,*args,**kwargs): 
    from multiprocessing.context import BaseContext 
    ctx = BaseContext() 
    ctx._name = "Name" 
    super(StdoutQueue,self).__init__(*args,**kwargs, ctx=ctx) 

EDIT2: Оказался документы имеют некоторую информацию о контексте here. Таким образом, вместо того, чтобы вручную создавать его, как я сделал это можно сделать

import multiprocessing 
ctx = multiprocessing.get_context() 

Это создаст надлежащий контекст с _name набором (к «вилке» в вашем конкретном случае), и вы можете передать его в очередь.

+0

Я пробовал в обоих направлениях (многопроцессорность.Queue и multiprocessing.queue.Queue), но никто не работает. –

+0

Привет @Darth Kotik, я добавил редактирование на мой вопрос. Там я показываю полный пример и подробное сообщение об ошибке. Вы работаете на Python 3.5? Было бы здорово, если бы вы могли воспроизвести ошибку :-) –

+0

Спасибо большое! Я попробую и дам вам знать, если это сработает :-) –

 Смежные вопросы

  • Нет связанных вопросов^_^