Python 如何使用可观察的RxPY间隔周期性地调用异步协同路由?

Python 如何使用可观察的RxPY间隔周期性地调用异步协同路由?,python,python-asyncio,reactivex,rx-py,Python,Python Asyncio,Reactivex,Rx Py,我需要创建一个可观察的流,该流定期发出异步协同路由的结果 intervalRead是一个函数,它返回一个可观察值,并将间隔rate和异步协同程序函数fun作为参数,需要在定义的间隔调用该函数 我的第一个方法是使用interval factory方法创建一个observable,然后使用map调用协同路由,使用from_future将其包装为observable,然后获取协同路由返回的值 async def foo(): 等待asyncio.sleep(1) 返回42 def intervalRe

我需要创建一个可观察的流,该流定期发出异步协同路由的结果

intervalRead
是一个函数,它返回一个可观察值,并将间隔
rate
和异步协同程序函数
fun
作为参数,需要在定义的间隔调用该函数

我的第一个方法是使用interval factory方法创建一个observable,然后使用map调用协同路由,使用from_future将其包装为observable,然后获取协同路由返回的值

async def foo():
等待asyncio.sleep(1)
返回42
def intervalRead(速率、乐趣)->可观察到:
loop=asyncio.get\u event\u loop()
返回接收间隔(速率)。管道(
映射(lambda i:rx.from_future(loop.create_task(fun()))),
)
异步def main():
obs=间隔读取(5,foo)
订阅(
on_next=lambda项目:打印(项目)
)
loop=asyncio.get\u event\u loop()
loop.create_任务(main())
loop.run_forever()
然而,我得到的输出并不是协程的结果,而是在指定的时间间隔发出的从未来返回的可观察结果

输出:

我怎样才能得到那个可观察的对象返回的实际值呢?我希望42岁

我的第二个想法是创建一个定制的可观察对象:


def间隔读取(速率、乐趣)->接收。可观察:
间隔=接收间隔(速率)
def SUB(观察员:观察员,调度程序=无):
loop=asyncio.get\u event\u loop()
def on_定时器(i):
任务=循环。创建任务(fun())
来自未来(任务)。订阅(
on_next=lambda i:观察者。on_next(i),
on_误差=λe:观察者。on_误差(e),
on_completed=lambda:print('coro completed')
)
订阅(on_next=on_定时器,on_error=lambda e:打印(e))
返回rx.create(subs)
但是,在订阅时,来自未来(任务)的订阅从不发出值,为什么会发生这种情况

但是如果我这样写
intervalRead

def intervalRead(速率、乐趣):
loop=asyncio.get\u event\u loop()
任务=循环。创建任务(fun())
从未来返回(任务)
我得到了预期的结果:
42
。显然,这并不能解决我的问题,但它让我困惑,为什么它在我的第二种方法中不起作用

最后,我使用
rx.concurrency CurrentThreadScheduler
尝试了第三种方法,并使用
schedule\u periodic
方法对操作进行了定期调度。然而,我面临着与第二种方法相同的问题

def funWithScheduler(速率、乐趣):
loop=asyncio.get\u event\u loop()
调度程序=CurrentThreadScheduler()
subject=rx.subjects.subject()
def操作(参数):
obs=rx.from_future(loop.create_task(fun()))。订阅(
on_next=lambda项目:主题。on_next(项目),
on_error=lambda e:print(f'error in action{e}'),
on_completed=lambda:print('操作已完成')
)     
obs.dispose()
计划程序。计划周期(速率、动作)
返回主题

如果您能深入了解我遗漏了什么,或提出任何其他建议来实现我的需求,我将不胜感激。这是我第一个使用asyncio和RxPY的项目,我只在angular项目的上下文中使用RxJS,因此欢迎提供任何帮助。

您的第一个示例几乎可以使用。只有两项更改才能使其正常工作:

首先,from_future的结果是一个可观察的,它发出一个项目(完成时的未来值)。所以map的输出是一个高阶的可观测值(一个发射可观测值的可观测值)。这些子观测值可以在贴图后使用merge_all操作符展平,或者使用flat_贴图代替贴图

然后,interval操作符必须在AsyncIO循环上调度其计时器,默认情况下并非如此:默认的调度程序是TimeoutScheduler,它生成一个新线程。因此,在原始代码中,无法在AsyncIO事件循环上调度任务,因为create_任务是从另一个线程调用的。在调用subscribe时使用scheduler参数将声明用于整个操作员链的默认调度器

以下代码有效(42每5秒打印一次):

import asyncio
import rx
import rx.operators as ops
from rx.scheduler.eventloop import AsyncIOScheduler


async def foo():
    await asyncio.sleep(1)
    return 42


def intervalRead(rate, fun) -> rx.Observable:
    loop = asyncio.get_event_loop()
    return rx.interval(rate).pipe(
        ops.map(lambda i: rx.from_future(loop.create_task(fun()))),
        ops.merge_all()
    )


async def main(loop):
    obs = intervalRead(5, foo)
    obs.subscribe(
        on_next=lambda item: print(item),
        scheduler=AsyncIOScheduler(loop)
    )

loop = asyncio.get_event_loop()
loop.create_task(main(loop))
loop.run_forever()