跳转到主要内容

基于AsyncIO的异步IO服务编程。

项目描述

Build status coverage BSD License Mode can be installed via wheel Supported Python versions. Supported Python implementations.

版本:

4.4.0

网页:

http://mode.readthedocs.org/

下载:

https://pypi.ac.cn/project/mode

源码:

http://github.com/ask/mode

关键词:

async, service, framework, actors, bootsteps, graph

什么是Mode?

Mode是一个基于AsyncIO之上的非常小巧的Python库,使使用变得更加容易。

在Mode中,你的程序由你可以启动、停止、重启和监督的服务构建。

服务只是一个类

class PageViewCache(Service):
    redis: Redis = None

    async def on_start(self) -> None:
        self.redis = connect_to_redis()

    async def update(self, url: str, n: int = 1) -> int:
        return await self.redis.incr(url, n)

    async def get(self, url: str) -> int:
        return await self.redis.get(url)

服务可以启动、停止和重启,并且有针对这些动作的回调函数。

它可以启动另一个服务

class App(Service):
    page_view_cache: PageViewCache = None

    async def on_start(self) -> None:
        await self.add_runtime_dependency(self.page_view_cache)

    @cached_property
    def page_view_cache(self) -> PageViewCache:
        return PageViewCache()

它可以包含后台任务

class PageViewCache(Service):

    @Service.timer(1.0)
    async def _update_cache(self) -> None:
        self.data = await cache.get('key')

依赖于其他服务的服务实际上形成了一个你可以可视化的图。

工作进程

Mode可选地提供了一个工作进程,你可以使用它来启动程序,支持日志记录、阻塞检测、远程调试等。

要启动工作进程,将以下内容添加到你的程序中

if __name__ == '__main__':
    from mode import Worker
    Worker(Service(), loglevel="info").execute_from_commandline()

然后执行你的程序以启动工作进程

$ python examples/tutorial.py
[2018-03-27 15:47:12,159: INFO]: [^Worker]: Starting...
[2018-03-27 15:47:12,160: INFO]: [^-AppService]: Starting...
[2018-03-27 15:47:12,160: INFO]: [^--Websockets]: Starting...
STARTING WEBSOCKET SERVER
[2018-03-27 15:47:12,161: INFO]: [^--UserCache]: Starting...
[2018-03-27 15:47:12,161: INFO]: [^--Webserver]: Starting...
[2018-03-27 15:47:12,164: INFO]: [^--Webserver]: Serving on port 8000
REMOVING EXPIRED USERS
REMOVING EXPIRED USERS

要停止它,按 Control-c

[2018-03-27 15:55:08,084: INFO]: [^Worker]: Stopping on signal received...
[2018-03-27 15:55:08,084: INFO]: [^Worker]: Stopping...
[2018-03-27 15:55:08,084: INFO]: [^-AppService]: Stopping...
[2018-03-27 15:55:08,084: INFO]: [^--UserCache]: Stopping...
REMOVING EXPIRED USERS
[2018-03-27 15:55:08,085: INFO]: [^Worker]: Gathering service tasks...
[2018-03-27 15:55:08,085: INFO]: [^--UserCache]: -Stopped!
[2018-03-27 15:55:08,085: INFO]: [^--Webserver]: Stopping...
[2018-03-27 15:55:08,085: INFO]: [^Worker]: Gathering all futures...
[2018-03-27 15:55:08,085: INFO]: [^--Webserver]: Closing server
[2018-03-27 15:55:08,086: INFO]: [^--Webserver]: Waiting for server to close handle
[2018-03-27 15:55:08,086: INFO]: [^--Webserver]: Shutting down web application
[2018-03-27 15:55:08,086: INFO]: [^--Webserver]: Waiting for handler to shut down
[2018-03-27 15:55:08,086: INFO]: [^--Webserver]: Cleanup
[2018-03-27 15:55:08,086: INFO]: [^--Webserver]: -Stopped!
[2018-03-27 15:55:08,086: INFO]: [^--Websockets]: Stopping...
[2018-03-27 15:55:08,086: INFO]: [^--Websockets]: -Stopped!
[2018-03-27 15:55:08,087: INFO]: [^-AppService]: -Stopped!
[2018-03-27 15:55:08,087: INFO]: [^Worker]: -Stopped!
信标

我们将传递给服务的信标对象会跟踪服务在图中的位置。

它们不是必需的,但可以用来可视化运行中的系统,例如,我们可以将其渲染成一个漂亮的图形。

这需要您安装pydot库和GraphViz。

$ pip install pydot

让我们修改应用程序服务类,使其在启动时将图形输出为图像。

class AppService(Service):

    async def on_start(self) -> None:
        print('APP STARTING')
        import pydot
        import io
        o = io.StringIO()
        beacon = self.app.beacon.root or self.app.beacon
        beacon.as_graph().to_dot(o)
        graph, = pydot.graph_from_dot_data(o.getvalue())
        print('WRITING GRAPH TO image.png')
        with open('image.png', 'wb') as fh:
            fh.write(graph.create_png())

创建服务

要定义服务,只需创建子类并填充在服务启动/停止等时的操作方法。

class MyService(Service):

    async def on_start(self) -> None:
        print('Im starting now')

    async def on_started(self) -> None:
        print('Im ready')

    async def on_stop(self) -> None:
        print('Im stopping now')

要启动服务,请调用await service.start()

await service.start()

或者,您可以使用mode.Worker(或其子类)从控制台启动基于异步的服务程序

if __name__ == '__main__':
    import mode
    worker = mode.Worker(
        MyService(),
        loglevel='INFO',
        logfile=None,
        daemon=False,
    )
    worker.execute_from_commandline()

这是一个图形!

服务可以启动其他服务、协程和后台任务。

  1. 使用add_dependency启动其他服务

    class MyService(Service):
    
        def __post_init__(self) -> None:
           self.add_dependency(OtherService(loop=self.loop))
  2. 使用on_init_dependencies启动一系列服务

    class MyService(Service):
    
        def on_init_dependencies(self) -> None:
            return [
                ServiceA(loop=self.loop),
                ServiceB(loop=self.loop),
                ServiceC(loop=self.loop),
            ]
  3. 启动一个将等待在停止时完成的未来/协程

    class MyService(Service):
    
        async def on_start(self) -> None:
            self.add_future(self.my_coro())
    
        async def my_coro(self) -> None:
            print('Executing coroutine')
  4. 启动一个后台任务

    class MyService(Service):
    
        @Service.task
        async def _my_coro(self) -> None:
            print('Executing coroutine')
  5. 启动一个持续运行的后台任务

    class MyService(Service):
    
        @Service.task
        async def _my_coro(self) -> None:
            while not self.should_stop:
                # NOTE: self.sleep will wait for one second, or
                #       until service stopped/crashed.
                await self.sleep(1.0)
                print('Background thread waking up')

安装

您可以通过Python包索引(PyPI)或从源代码安装Mode。

使用pip安装

$ pip install -U mode

从源代码下载和安装

https://pypi.ac.cn/project/mode下载Mode的最新版本

您可以按照以下步骤进行安装

$ tar xvfz mode-0.0.0.tar.gz
$ cd mode-0.0.0
$ python setup.py build
# python setup.py install

如果您当前没有使用虚拟环境,则最后一个命令必须以特权用户执行。

使用开发版本

使用pip

您可以使用以下pip命令安装Mode的最新快照

$ pip install https://github.com/ask/mode/zipball/master#egg=mode

常见问题解答

我可以将Mode与Django/Flask等一起使用吗?

是的!使用gevent/eventlet作为与asyncio集成的桥梁。

使用gevent

这与任何可以与gevent一起工作的阻塞Python库兼容。

使用gevent需要您安装aiogevent模块,您可以将它作为Mode的捆绑包一起安装

$ pip install -U mode[gevent]

然后,为了实际使用gevent作为事件循环,您必须在入口模块(通常是启动工作的地方)中执行以下操作,在导入任何其他第三方库之前

#!/usr/bin/env python3
import mode.loop
mode.loop.use('gevent')
# execute program

记住:这必须位于模块的顶部,以确保它在导入其他库之前执行。

使用eventlet

这与任何可以与eventlet一起工作的阻塞Python库兼容。

使用eventlet需要您安装aioeventlet模块,您可以将它作为Mode的捆绑包一起安装

$ pip install -U mode[eventlet]

然后,为了实际使用eventlet作为事件循环,您必须在入口模块(通常是启动工作的地方)中执行以下操作,在导入任何其他第三方库之前

#!/usr/bin/env python3
import mode.loop
mode.loop.use('eventlet')
# execute program

记住:这非常重要,它必须位于模块的顶部,并且必须在导入库之前执行。

我可以将Mode与Tornado一起使用吗?

是的!使用tornado.platform.asyncio桥接:https://tornado.pythonlang.cn/en/stable/asyncio.html

我可以将Mode与Twisted一起使用吗?

是的!使用asyncio反应器实现:https://twistedmatrix.com/documents/17.1.0/api/twisted.internet.asyncioreactor.html

您将支持Python 3.5或更早的版本吗?

没有立即支持Python 3.5的计划,但您欢迎为项目做出贡献。

以下是完成此操作所需的一些步骤

  • 源代码转换以将变量注释重写为注释

    例如,代码

         class Point:
             x: int = 0
             y: int = 0
    
    must be rewritten into::
    
         class Point:
             x = 0  # type: int
             y = 0  # type: int
  • 源代码转换以重写异步函数

    例如,代码

    async def foo():
        await asyncio.sleep(1.0)

    必须重写为

    @coroutine
    def foo():
        yield from asyncio.sleep(1.0)

您将支持Python 2吗?

目前没有计划支持Python 2,但欢迎您为项目做出贡献(上述问题中的细节也适用于Python 2)。

在关机时我收到很多警告,这是怎么回事?

如果您在关机时收到此类警告

Task was destroyed but it is pending!
task: <Task pending coro=<Service._execute_task() running at /opt/devel/mode/mode/services.py:643> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x1100a7468>()]>>
Task was destroyed but it is pending!
task: <Task pending coro=<Service._execute_task() running at /opt/devel/mode/mode/services.py:643> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x1100a72e8>()]>>
Task was destroyed but it is pending!
task: <Task pending coro=<Service._execute_task() running at /opt/devel/mode/mode/services.py:643> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x1100a7678>()]>>
Task was destroyed but it is pending!
task: <Task pending coro=<Event.wait() running at /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/asyncio/locks.py:269> cb=[_release_waiter(<Future pendi...1100a7468>()]>)() at /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/asyncio/tasks.py:316]>
Task was destroyed but it is pending!
    task: <Task pending coro=<Event.wait() running at /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/asyncio/locks.py:269> cb=[_release_waiter(<Future pendi...1100a7678>()]>)() at /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/asyncio/tasks.py:316]>

通常意味着您在进程退出前忘记停止某个服务。

行为准则

所有与项目代码库、问题跟踪器、聊天室和邮件列表互动的人士都应遵守Mode行为准则。

作为这些项目的贡献者和维护者,以及为了培养一个开放和欢迎的社区,我们承诺尊重所有通过报告问题、发布功能请求、更新文档、提交拉取请求或补丁等方式做出贡献的人。

我们致力于确保每个人都能在这些项目中获得一个没有骚扰的参与体验,无论经验水平、性别、性别认同和表达、性取向、残疾、个人外貌、体型、种族、民族、年龄、宗教或国籍。

参与者不可接受的行为示例包括

  • 使用性化语言或图像

  • 人身攻击

  • 骚扰或侮辱/贬低性评论

  • 公开或私下骚扰

  • 未经明确许可发布他人的个人信息,如物理或电子地址

  • 其他不道德或不专业的行为。

项目维护者有权和义务移除、编辑或拒绝不符合本行为准则的评论、提交、代码、维基编辑、问题和其他贡献。通过采用本行为准则,项目维护者承诺将公平和一致地应用这些原则到管理本项目的各个方面。不遵守或执行本行为准则的项目维护者可能会被永久移出项目团队。

本行为准则适用于项目空间以及个人代表项目或其社区时的公共空间。

可以通过打开问题或联系一个或多个项目维护者来报告滥用、骚扰或其他不可接受的行为。

本行为准则借鉴了贡献者公约,版本1.2.0,可在以下链接找到:http://contributor-covenant.org/version/1/2/0/

项目详情


发布历史 发布通知 | RSS源

下载文件

下载您平台对应的文件。如果您不确定选择哪个,请了解更多关于安装包的信息

源代码分发

mode-4.4.0.tar.gz (275.5 kB 查看哈希值)

上传时间 源代码

构建分发

mode-4.4.0-py2.py3-none-any.whl (100.6 kB 查看哈希值)

上传时间 Python 2 Python 3

由以下组织支持