2016-07-18 3 views
0

Я хотел бы подкласса Future класс модуля concurrent Python.Подкласс будущего класса

Документы:

Будущего класс инкапсулирует асинхронное выполнение вызываемого. Будущие экземпляры создаются Executor.submit().

Документы Executor не объясняют, где взять класс Future.

... Как заставить команду Executor.submit() принять мой пользовательский класс будущего?

Зачем мне это нужно?

Мне нравится OOP, так как он создает читаемый код. Я хотел бы результат выглядеть следующим образом:

for my_future in concurrent.futures.as_completed(...): 
    my_future.my_custom_method() 
+0

Зачем вам это нужно? Что делает ваше будущее? – Elazar

+0

О, это * ужасная * причина делать подклассы. Не. – Elazar

+0

@ Элазар, пожалуйста, объясните, почему это ужасно. – guettli

ответ

1

Рассматривая код, ProcessPoolExecutor.submit() и ThreadPollExecutor.submit(), возвращает экземпляр Future, который определен в conccurent.futures._base.Future.

Итак, вот трюк. Вы можете подклассом и заменить исходное Будущее, а затем добавить пользовательские методы в подкласс.

Это выполнимо, но не рекомендуется. Для этой цели лучше использовать композицию, а не наследование. Существует хорошая глава о наследовании и композиции в Learn Python the Hard Way

Назад к вопросу, здесь есть композиция пример:

class Myclass(object): 
    def __init__(self, workers=3): 
     self.executor = concurrent.futures.ProcessPoolExcutor(workers) 

    def run(self, job): 
     '''Job to be run in a Executor''' 

    def submit(self, jobs): 
     self.futures = [executor.submit(self, foo, job) for job in jobs] 

    def done(self, result): 
     '''Dealing with the result''' 

    def harvest(self): 
     for my_future in concurrent.futures.as_completed(self.futures): 
      self.done(my_future.result()) 

И тогда вы можете создать подкласс MyClass и реализации другого метода Выполненные.

+0

Да, это работает. Я просто спрашиваю себя, почему библиотека не была реализована с учетом подкласса. Метод 'as_completed()' возвращает фьючерсы. Для этого нужен бесполезный код. Да, для этого случая применяется ваше предложение «Лучше использовать композицию, а не наследование для этой цели». Но это применимо только тогда, когда код восходящего потока не обеспечивает простой способ для подкласса. Не поймите меня неправильно. Это не твоя вина. Спасибо за ваш ответ! – guettli

+0

@guettli Добро пожаловать. Из https://www.python.org/dev/peps/pep-3148/#rationale мы можем знать, что на фьючерсный модуль Python в значительной степени повлиял пакет java.util.concurrent. Не важно, почему восходящий поток не обеспечивает простой способ для подкласса. Возможно, вверх по потоку хотят, чтобы это было просто, возможно, подкласс не является основным требованием, или, возможно, это уже сделано. Нет совершенной вещи [пожал плечами]. – duyue

1

Использование конкретного класса Future является зашитым в Executor.submit() (будь processes или threads). Поэтому я не думаю, что можно делать именно то, что вы просите. Тем не менее, вы можете вернуть любой результат из вызываемого, переданного в Executor.submit(). Поэтому поставить свои собственные методы в пользовательском классе возврата:

class my_result(object): 
    def my_custom_method(self): 
     pass 

def x(): 
    return my_result() 

with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor: 
    futures = [executor.submit(x), executor.submit(x)] 
    for my_future in concurrent.futures.as_completed(futures): 
     my_future.result().my_custom_method() 
       # ^^^^^^^^^ 

Edit Или, если вы действительно хотите, чтобы ваш внутренний цикл, чтобы быть чистым, измените последние две строки:

for my_result in (f.result() for f in concurrent.futures.as_completed(futures)): 
        # ^^^^^^^^^^^^^^^^^^^^ 
     my_result.my_custom_method() 

generator expression(f.result() ... (futures)) принимает итератор фьючерсов от as_completed и дает вам итератор результатов этих фьючерсов. Затем вы можете выполнить эти результаты.

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