如何在Twisted中使用异步生成器?

时间:2018-03-13 17:47:17

标签: python python-3.x twisted twisted.internet

Twisted提供了包装本地协程(使用async / await的协同程序)。使用ensureDeferred,我们可以包装一个协同程序并获得它的等效延迟。如何包装一个异步生成器(在Python 3.6中可用),以便我们得到一个延迟的?

尝试包装异步对象会返回以下错误:

File "/home/yash/Scrapy/vnv/lib/python3.6/site-packages/Twisted-17.9.0-py3.6-linux-x86_64.egg/twisted/internet/defer.py", line 915, in ensureDeferred
raise ValueError("%r is not a coroutine or a Deferred" % (coro,))

ValueError:不是协程或延迟

编辑:我提供了一个示例代码,其中演示了所需的逻辑,并发生了相应的错误:

from twisted.internet import reactor, defer
import asyncio


async def start_request():
   urls = ['https://example.com/page/1',
           'https://example.com/page/2',
           'https://example.com/page/3']

   async for url in urls:
       yield url
       await asyncio.sleep(2)


async def after_request():
   await asyncio.sleep(3)
   print("Completed the work")


deferred = ensureDeferred(start_request())
deferred.addCallback(after_request())
print("reactor has started")
reactor.run()

错误追溯:

Traceback (most recent call last):
File "req2.py", line 20, in <module>
deferred = defer.ensureDeferred(start_request())
File "/home/yash/Scrapy/vnv/lib/python3.6/site-packages/Twisted-
17.9.0-py3.6-linux-x86_64.egg/twisted/internet/defer.py", line 915, in 
ensureDeferred
raise ValueError("%r is not a coroutine or a Deferred" % (coro,))
ValueError: <async_generator object start_request at 0x7febb282cf50> 
is not a coroutine or a Deferred

1 个答案:

答案 0 :(得分:0)

您提供的示例存在一些问题。第一个是导致你看到的错误,另一个会导致问题

第一个是如果你在异步函数中使用yield,它不再是一个协程,它是一个生成器函数。所以,你传递给ensureDeferred的不是协程,导致你看到的错误。而不是yield url,尝试只打印,或在列表中收集它们并稍后返回。

第二个问题是你可以直接使用async / await和twisted,而不是asyncio。想要调用asyncio函数的Twisted代码必须首先将asyncio Futures转换为Deferreds。由于asyncio.sleep为您提供了协程,因此您需要首先使用Future 转换为asyncio.ensure_future,然后将Future转换为{ {1}},Deferred.fromFuture。或者您可以使用twisted来模拟睡眠,如下所示:

Deferred

第三个问题是你不能将def sleep(secs): d = Deferred() reactor.callLater(secs, d.callback, None) return d 用于不是异步迭代器的东西,所以async for应该只是async for url in urls:

P.S:感谢来自Freenode上#twisted频道的@runciter和@jfhbrook的帮助,这个=)