Поведение Пикки с установщиками @property - PullRequest
0 голосов
/ 04 июля 2018

Я играю с актерской моделью Пикки и обнаружил забавное поведение. Вот демо, которое

  1. Запускает актера
  2. Получает прокси для него
  3. Устанавливает одно из его свойств @ 1008 *

Вот код:

import time
import pykka

from sys import version_info as python_version
if python_version > (3, 0):
    from _thread import get_ident
else:
    from thread import get_ident

startTime = time.time()

def debug(msg, prefix='MSG'):
    msgProc = "%s (thread #%s @ t = %.2fs): %s" % (prefix,get_ident(), time.time() - startTime, msg)
    print(msgProc)

def mainThread():

    debug('Launching support actor...', prefix='MAIN')
    supportRef = supportThread.start()

    debug('Getting support proxy...', prefix='MAIN')
    supportProxy = supportRef.proxy()

    debug('Getting myVal obj...', prefix='MAIN')
    obj = supportProxy.myVal
    debug(obj, prefix='MAIN')

    debug('Setting myVal obj...', prefix='MAIN')
    supportProxy.myVal = 2

    debug('Setting myVal obj...', prefix='MAIN')
    supportProxy.myVal = 3

    supportProxy.stop()


class supportThread(pykka.ThreadingActor):

    def __init__(self):
        super(supportThread, self).__init__()

        self._myVal = 0

    @property
    def myVal(self):
       debug("Getting value", prefix='SUPPORT')
       return self._myVal

    @myVal.setter
    def myVal(self, value):

       debug("Setting value: processing for 1s...", prefix='SUPPORT')
       time.sleep(1)

       debug("Setting value: done", prefix='SUPPORT')
       self._myVal = value

mainThread()

Вывод выглядит так:

MAIN (thread #16344 @ t = 0.00s): Launching support actor...
MAIN (thread #16344 @ t = 0.00s): Getting support proxy...
SUPPORT (thread #16344 @ t = 0.00s): Getting value
MAIN (thread #16344 @ t = 0.00s): Getting myVal obj...
MAIN (thread #16344 @ t = 0.00s): <pykka.threading.ThreadingFuture object at 0x0000000002998518>
MAIN (thread #16344 @ t = 0.00s): Setting myVal obj...
SUPPORT (thread #16248 @ t = 0.00s): Getting value
SUPPORT (thread #16248 @ t = 0.00s): Setting value: processing for 1s...
SUPPORT (thread #16248 @ t = 1.00s): Setting value: done
MAIN (thread #16344 @ t = 1.00s): Setting myVal obj...
SUPPORT (thread #16248 @ t = 1.01s): Setting value: processing for 1s...
SUPPORT (thread #16248 @ t = 2.01s): Setting value: done
[Finished in 2.3s]

У меня есть пара вопросов здесь.

  1. Почему метод get supportThread.myVal() вызывается в контексте основного потока, когда вызывается .proxy()?
  2. Почему строки supportProxy.myVal = <a new value> приводят к тому, что основной поток ожидает завершения актера?

Мне это кажется ошибкой: я думал, что прокси должен блокировать выполнение только если .get() вызывается в ThreadingFuture. Или это предназначено?

1 Ответ

0 голосов
/ 09 июля 2018

Отказ от ответственности: я автор Pykka.

В сторону: Pykka не мертва, она просто отлично работает для того, для чего она была создана: предоставляя абстракцию параллелизма для музыкального сервера Mopidy и его 100+ расширений.

Поведение Пикки со свойствами не является оптимальным, но есть причина, по которой это так.

  1. Чтобы создать прокси-объект, Pykka должен проанализировать API целевого объекта. При проверке, являются ли доступные для целевого объекта атрибуты вызываемыми, атрибутами или «проходимыми атрибутами», getattr() вызывается один раз для каждого атрибута. Это заставляет свойство get вызываться. См. Proxy._get_attributes() и Actor._get_attribute_from_path() для.

  2. Поскольку в Python нет способа получить возвращаемое значение из установщика свойств, настройка свойства на прокси-сервере Pykka принимает безопасное заданное по умолчанию ожидание завершения для установщика, так что любые исключения, возникшие в установщике, могут быть повторно обработаны. на сайте звонка в mainThread(). Альтернативой было бы оставить любые исключения, вызванные установщиками свойств, необработанными. Подробнее см. Proxy.__setattr__().

Таким образом, свойства «работают» с Pykka, но вы получаете больший контроль, используя вызовы методов, так как вы всегда получаете будущее и можете сами решить, ждать вам результата или нет.

Независимо от того, используете ли вы Pykka или нет, я считаю хорошей практикой не выполнять дорогостоящую работу по получению свойств, а вместо этого использовать надлежащие методы для выполнения «дорогой» работы.

Дизайн API напрямую влияет на то, как ваши пользователи будут использовать API:

  • Объект со свойством приглашает к повторному использованию одного и того же свойства и, следовательно, к повторному пересчету. Сохраняйте свойства мертвыми простыми и дешевыми.
  • Объект, представляющий метод, возвращающий результат, обычно приводит к тому, что вызывающая сторона сохраняет результат в переменной и повторно использует один и тот же результат вместо вызова метода несколько раз. Используйте методы для любой нетривиальной работы. Если это действительно дорого, рассмотрите другой префикс, отличающийся от get_, например load_, fetch_ или calculate_, что дополнительно указывает на то, что пользователь должен держать указатель на результат и использовать его повторно.

Чтобы самому следовать этим принципам, основной API Mopidy давно перешел от использования множества свойств к использованию методов получения и установки. В следующем основном выпуске все свойства будут удалены из основного API Mopidy. Благодаря тому, как работает создание прокси, эта очистка значительно сократит время запуска Mopidy.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...