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
答案 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的帮助,这个=)