V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
oahebky
V2EX  ›  Python

状态模式和事件触发切换状态可以整合什么库来做 Python 程序设计?

  •  
  •   oahebky · 2020-04-30 11:05:51 +08:00 · 2524 次点击
    这是一个创建于 1450 天前的主题,其中的信息可能已经有所发展或是发生改变。

    一个程序针对有(一堆) object(s) 的不同状态执行不同的 actions ( functions )。

    但是状态的切换是来自外部事件(非 http 请求,不过转换成 http 请求也 OK )触发。 外部事件触发可以做成 1. http 请求,2. 消息队列同步 等等

    手写一个状态模式应该不算问题,设计模式的实现大同小异。

    但是外部事件触发应该怎么做才好??? 就是用什么库写起来代码“很自然”。

    举个例子:

    比如我大学做过一个 MFC 应用,即,写的是 C++ 的桌面程序,点击按钮的事件触发 MFC 框架都生成做好了,然后只需要对按钮的 handler 函数编写实现即可。



    之所以有这个问题是因为我还没有怎么写过 python 的事件触发程序(非桌面程序,非 web 程序,一个后台 daemon 程序),所以不清楚“最佳实践”是怎么样的?

    10 条回复    2020-05-04 11:41:45 +08:00
    ClericPy
        1
    ClericPy  
       2020-04-30 11:09:51 +08:00
    事件驱动用 pyee
    oahebky
        2
    oahebky  
    OP
       2020-04-30 11:11:30 +08:00
    @ClericPy #1 原文:“事件驱动用 pyee”
    ======
    回复:OK,我马上去了解一下。
    bwangel
        3
    bwangel  
       2020-04-30 11:21:25 +08:00
    https://github.com/jek/blinker

    blinker 可以用来定义事件。不过这个都是同步的。

    可以再描述一下详细需求么?内部状态切换是否是耗时较长任务,如果耗时较长,需要上队列。
    oahebky
        4
    oahebky  
    OP
       2020-04-30 11:31:02 +08:00
    @bwangel #3 原文:“https://github.com/jek/blinkerblinker 可以用来定义事件。不过这个都是同步的。可以再描述一下详细需求么?内部状态切换是否是耗时较长任务,如果耗时较长,需要上队列。”
    ======
    回复:一个 object 内有不同的状态,
    有的状态切换时间长(处于几小时,几天后的等待状态),有的状态切换时间短 - 计算或网络请求。

    简化状态其实也就是:

    状态 1 -> 状态 1 的行为 - 等待 -> 外部事件触发 => 切换到状态 2
    状态 2 -> 状态 2 的行为 - 计算得到结果 => 切换到状态 1

    就是切换状态不是单纯的状态模式里面的函数执行结束或者 sleep 就切换,
    而是来自外部的事件(其它 python 进程对它)触发,

    就是这一点不清楚选择什么样的库写起来比较不会重复造轮子。
    brucedone
        5
    brucedone  
       2020-04-30 13:05:53 +08:00
    qile1
        6
    qile1  
       2020-05-01 00:27:34 +08:00 via Android
    感觉这个有点像微信公众号 回复消息的使用
    不过那个不会几个小时执行
    oahebky
        7
    oahebky  
    OP
       2020-05-01 12:42:22 +08:00
    @bwangel
    后来我思考了一下,对于我来说,使用哪种程序设计更像是程序是 C 端还是 S 端的问题。

    如果是 S 端的话(比如电脑桌面程序相对于用户性质上也是 S 端),那么使用你推荐的 blinker 应该是很好的选择(我把它 star 了,谢谢)。

    如果是 C 端的话,主要是一个请求主动发出去,等待响应。
    在我的实际情况上,更像 C 端。

    不过怎么做到异步是我正在研究的,因为 rabbitMQ 的 pika 和 aio-pika 我都还没好好使用过,之前只是了解到。
    oahebky
        8
    oahebky  
    OP
       2020-05-01 12:53:53 +08:00
    @brucedone
    这个库还在学怎么用,应该可以少写不少重复的代码。

    后来想了想,对于我自己的问题,难点在于怎么做到异步。
    当时提问的时候默认意思就是异步执行许多个具有状态模式设计的对象,原文没有说清楚;因为觉得解决了同步的状态模式循环,事件触发,就能加入 asyncio 迁移成异步。

    但是后来发现我就是不知道怎么做到不同的触发事件(非 sleep,非 http request )怎么 yield 出去,后来想来我应该主要是要解决学会 aio-pika 怎么使用的问题。
    bwangel
        9
    bwangel  
       2020-05-04 11:29:14 +08:00
    @oahebky

    感觉你这个状态切换的模型没必要用库,因为状态变更的逻辑你始终都是要写的,可以直接手撸一个。

    如果是 HTTP 请求触发的话,需要考虑一下并发问题,一个状态正在执行切换过程中,又有一个 HTTP 请求进来了。

    所以,建议

    当 HTTP 请求进来后,不立刻执行状态切换的操作,而是将它包装成一个事件,放到一个队列中,另外再起一个 Worker (可以用多个 Worker,根据你的实际情况确定,不会发生冲突即可),执行状态切换的操作。这样状态切换操作的执行时间过长,也不会有什么问题.


    事件+队列可以直接使用 RabbitMQ + Celery (千万别用 Redis+Celery,不成熟,有 bug)。如果觉得这两个太重,而业务量又不是太大的话,可以用 MySQL 自己写一个队列。
    oahebky
        10
    oahebky  
    OP
       2020-05-04 11:41:45 +08:00
    @bwangel
    这么设计这个程序我想了几天了(自己业余为了学习做项目),重新学了学 python 异步,可以说得出的结论和你完全一致。

    其实我最初是在纠结怎么在单个异步线程中,创建的以万为单位的(含有状态切换的)对象之间调度。
    后来发现要用 rabbitmq 的话,相当于要创建出同数量的 queue ;
    否则的话就要自己造一个基于对象 ID 的 loop 库 -- 对含有 ID 的 message 用 gener.send(msg) 激活对应的 gener 。

    不论哪种方式都有些过度了。

    所以还是读到带 ID 的 message 之后,重新创建对象,执行完任务销毁对象,loop 回去等待消息队列;这样设计目前来看是合理的。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2991 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 11:07 · PVG 19:07 · LAX 04:07 · JFK 07:07
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.