当前位置: 首页 > 知识库问答 >
问题:

在asyncio中链接协程(和观察者模式)

李文轩
2023-03-14

我很难理解协同程序是如何链接在一起的。在一个比hello world或factorials稍微简单一些的示例中,我希望有一个循环,它可以持续监视文件修改时间,然后在触摸文件时打印出时间:

#!/usr/bin/env python3
import os
import asyncio

@asyncio.coroutine
def pathmonitor(path):
    modtime = os.path.getmtime(path)
    while True:
        new_time = os.path.getmtime(path)
        if new_time != modtime:
            modtime = new_time
            yield modtime
        yield from asyncio.sleep(1)

@asyncio.coroutine
def printer():
    while True:
        modtime = yield from pathmonitor('/home/users/gnr/tempfile')
        print(modtime)

loop = asyncio.get_event_loop()
loop.run_until_complete(printer())
loop.run_forever()

我希望这可以工作-然而,当我运行它时,我得到一个:

RuntimeError: Task got bad yield: 1426449327.2590399

我做错了什么?

更新:请参阅下面我的答案,以了解观察者模式的示例(即,当文件被触动时,有效地允许多个注册者获取更新),而无需使用回调(您必须使用任务)。

UPDATE2:有一个更好的解决方案:3.5的async for(异步迭代器):https://www.python.org/dev/peps/pep-0492/

共有2个答案

裴承安
2023-03-14

正如其他人指出的那样,我的错误是,我试图像发电机一样使用协同程序。我需要创建多个协程,而不是依赖生成器进行迭代。此外,我需要使用任务来实现观察者模式,而不需要回调,因为多个注册者可以从同一个任务中产生。我的pathmonitor看起来像这样:

import os
import asyncio

class PathInfo:

    def __init__(self, path):
        self.path = path
        self.modtime = os.path.getmtime(path)
        self.startTask()

    def startTask(self):
        self.task = asyncio.async(self._checkIfTouched())

    def _checkIfTouched(self):
        while True:
            yield from asyncio.sleep(1)
            newtime = os.path.getmtime(self.path)
            if self.modtime != newtime:
                self.modtime = newtime
                return newtime

class PathMonitor:

    def __init__(self):
        self._info = {}

    @asyncio.coroutine
    def wasTouched(self, path):
        try:
            info = self._info[path]
        except KeyError:
            self._info[path] = info = PathInfo(path)
        if info.task.done():
            info.startTask()
        modtime = yield from info.task
        return modtime

def printer():
    while True:
        modtime = yield from mon.wasTouched('/tmp/myfile')
        print(modtime)

mon = PathMonitor()

loop = asyncio.get_event_loop()
asyncio.async(printer())
loop.run_forever()
卢杰
2023-03-14

我通过在链式协同路由中使用return而不是yield来运行代码,就像链式协同路由示例一样:

#!/usr/bin/env python3
import os
import asyncio2

@asyncio.coroutine
def pathmonitor(path):
    modtime = os.path.getmtime(path)
    while True:
        new_time = os.path.getmtime(path)
        if new_time != modtime:
            modtime = new_time
            return modtime
        yield from asyncio.sleep(1)


@asyncio.coroutine
def printer():
    while True:
        modtime = yield from pathmonitor('/tmp/foo.txt')
        print(modtime)


loop = asyncio.get_event_loop()
loop.run_until_complete(printer())
loop.run_forever()

请注意,打印机()的循环将为每次迭代创建一个新的路径监视器生成器。不确定这是否是您想要的,但这可能是一个开始。

我发现协程API和语法让我自己有点困惑。以下是一些我觉得有用的阅读材料:

  • Python 3.3中的新增功能:“PEP 380:委托给子生成器的语法”
  • PEP380:"形式语义学"
  • asyncio:"示例:链协程"
  • Greg Ewing的“二叉树”例子

 类似资料:
  • 是否有一种设计模式可以形成一个“复合”观察者/可观察者? 我的意思是我有一个可观察的,它在某个变化时通知它的监听器。 每个监听器也是一个可观察的,并通知它自己的监听器(在某个动作上,它做了哪个动作是由第一个可观察的通知触发的)。 这种观察者/可观察的“链接”作为设计是可以的,还是有一个标准的模式?

  • 主要内容:介绍,实现,Subject.java,Observer.java,BinaryObserver.java,OctalObserver.java,HexaObserver.java,ObserverPatternDemo.java当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式。 介绍 意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知

  • 观察者模式 亦称: 事件订阅者、监听者、Event-Subscriber、Listener、Observer 意图 观察者模式是一种行为设计模式, 允许你定义一种订阅机制, 可在对象事件发生时通知多个 “观察” 该对象的其他对象。 问题 假如你有两种类型的对象: ​ 顾客和 商店 。 顾客对某个特定品牌的产品非常感兴趣 (例如最新型号的 iPhone 手机), 而该产品很快将会在商店里出售。 顾客

  • 一、定义 观察者模式(发布-订阅模式):其定义对象间一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。 在JavaScript中,一般使用事件模型来替代传统的观察者模式。 好处: (1)可广泛应用于异步编程中,是一种替代传递回调函数的方案。 (2)可取代对象之间硬编码的通知机制,一个对象不用再显示地调用另外一个对象的某个接口。两对象轻松解耦。 二、DOM事件–观察者

  • 当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。 介绍 意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。 主要解决:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。 何时使用:一个对象(目标对象)

  • 观察者模式是软件设计模式的一种。在此种模式中,一个目标对象管理所有相依于它的观察者对象,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实时事件处理系统。 定义一个目标构造函数,并实现绑定、解绑和触发等方法: function Subject() { this.events = {}; this.count = 0; }​ Subj