首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Pykka对“属性设置者”的行为

Pykka对“属性设置者”的行为
EN

Stack Overflow用户
提问于 2018-07-04 09:59:47
回答 1查看 125关注 0票数 0

我在玩皮卡的演员模型,发现了一些有趣的行为。这里有一个演示

  1. 启动一个演员
  2. 获取它的代理。
  3. 设置其@属性之一

下面是代码:

代码语言:javascript
复制
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()

输出如下所示:

代码语言:javascript
复制
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. 为什么当调用supportThread.myVal()时,getter .proxy()在主线程的上下文中被调用?
  2. 为什么行supportProxy.myVal = <a new value>会导致主线程等待参与者完成?

在我看来,这似乎是一个bug :我认为,只有当.get()在ThreadingFuture上被调用时,代理才应该阻止执行。或者这是故意的?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-07-09 08:50:47

免责声明:我是Pykka的作者。

旁白: Pykka并没有死,它只是对它所做的工作很好:为Mopidy音乐服务器及其100+扩展提供一个并发抽象。

Pykka对属性的行为不是最优的,但这是有原因的。

  1. 要创建代理对象,Pykka必须内省目标对象的API。在测试目标对象上可用的属性是否为可调用属性、属性或“可遍历属性”时,对每个属性调用一次getattr()。这将导致调用属性getter。请参阅Proxy._get_attributes()Actor._get_attribute_from_path()
  2. 由于Python中没有从属性设置器获取返回值的方法,因此Pykka代理上的属性设置采用了安全的默认设置,即等待setter完成,以便在mainThread()中的调用站点上重新显示在setter中引发的任何异常。另一种方法是保留由属性设置程序引发的任何例外情况不被处理。详情请参见Proxy.__setattr__()

总之,属性对Pykka“起作用”,但是您可以通过使用方法调用获得更多的控制,因为这样您就可以得到一个将来的返回,并且可以决定自己是否需要等待结果。

不管您是否使用Pykka,我发现在属性获取器中不执行任何昂贵的工作是很好的做法,而是使用适当的方法来完成“昂贵”的工作。

API设计直接影响用户如何使用API:

  • 具有属性的对象将重复使用同一属性,从而重复重新计算。让房产简便易行,便宜。
  • 公开返回结果的方法的对象通常会导致调用方将结果保存在变量中,并重用相同的结果,而不是多次调用该方法。对任何非琐碎的工作使用方法。如果它真的很昂贵,请考虑另一个比get_前缀,例如load_fetch_calculate_,进一步表明用户应该保留结果的句柄并重用它。

为了遵循这些原则,Mopidy的核心API很久以前就从使用大量属性迁移到使用getter和setter。在下一个主要版本中,所有属性都将从Mopidy的核心API中删除。由于代理创建的方式,这种清理将大大减少Mopidy的启动时间。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51170941

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档