(python 3.6.4和龙卷风4.5.3)
使用时: http_client = tornado.httpclient.AsyncHTTPClient() 异步http请求获取工作正常。
但是,在运行程序时,尝试定义和使用AsyncHTTPClient的子类会让我陷入某种死锁状态(而不是同步的HTTPClient类,其中的子类运行良好)
*请纠正我:如果Tornado的AsynchHTTPClient类遵循/继承自Configurable接口/抽象类,那么如何从中构建对象呢? (与Java中的规则相同?)。是不是某种东西在几个内置的东西中选择了一个默认的实现?
"可配置的子类必须定义类方法configurable_base和configurable_default,并使用实例方法初始化而不是 init 。 " - 继承的默认ctor是否会调用super。 init ?这是问题的原因吗?
从文档看来,不推荐继承AsyncHTTPClient /不是使用它的有效方法:
http_client = AsyncHTTPClient()
http_client.fetch("http://www.google.com/", handle_response)
这个类的构造函数在几个方面都很神奇:它
实际上创建了一个特定于实现的实例
子类,实例被重用为一种伪单例
(每.IOLoop
一个)。关键字参数force_instance=True
可用于抑制此单例行为。除非
使用force_instance=True
,不应传递任何参数
AsyncHTTPClient
构造函数。实现子类为
以及可以使用static设置其构造函数的参数
方法configure()
所有AsyncHTTPClient
实施都支持defaults
keyword参数,可用于设置默认值
HTTPRequest
个属性。例如::
AsyncHTTPClient.configure(
None, defaults=dict(user_agent="MyUserAgent"))
# or with force_instance:
client = AsyncHTTPClient(force_instance=True,
defaults=dict(user_agent="MyUserAgent"))
其他问题:
1)缓冲响应是否是一个选择问题?
3)我什么时候应该使用tornado.web.RequestHandler?
这个类目前没有错误但我在实际获取后没有收到回复。
import sys
from tornado import ioloop, gen, httpclient
在SimpleAsyncHTTPClient类(httpclient.AsyncHTTPClient)下:
#had to add this one (abstract function empty implementation? )
# I think that's the troublemaker
def fetch_impl(self, request, callback):
pass
@gen.coroutine
def get(self, url):
method = 'GET'
print('send Async GET request ')
res = yield self._fetch(url, method)
print('after _fetch ...')
return res
@gen.coroutine
def _fetch(self, url, method):
print('send Asynchronous request ...')
res = yield self.fetch(url, method=method)
print('got a response')
return res
在全球范围内:
@ gen.coroutine
def ioloop_task():
yield gen.sleep(3)
url = 'http://google.com'
http_client = SimpleAsyncHTTPClient()
res = yield http_client.get(url)
res_code = res.code
res_body = res.body
print('return code: {}, body: {}....'.format(res_code, res_body[:60]))
print('do other stuff ....')
yield gen.sleep(2)
print(' task completed')
答案 0 :(得分:0)
但为什么呢?您可以使用AsyncHTTPClient
。
如果你这样做是为了学习,这里是概念的概述:
yield
和await
用于暂停协程。但他们不一样。但是,在Tornado中,当yield
关键字位于gen.coroutine
修饰函数中时,它们都执行相同的操作 - 即挂起协程直到将来(或awaitable)完成。
return
用于从函数返回一些东西,我相信你已经知道了。
何时使用yield
以及何时使用await
?
如果您使用的是早于3.5的Python,请使用@gen.coroutine ... yield
语法。对于3.5+,您应该使用async def ... await
语法。此外,Tornado即将发布drop support for older Python版本,因此最好遵守新语法。
这让我指出混合这两者似乎并不是一个好主意。通过将@gen.coroutine
替换为async
并将yield
替换为await
来摆脱旧语法。
关于您的代码的一些评论:
我们来看看_fetch
和get
方法。他们俩都没有回来。
详细说明一下,get
方法res = await self._fetch(url, method)
res
None
将_fetch
ioloop_task
,因为res = http_client.get(url)
没有返回任何内容。
res
None
get
也发生了同样的情况。 res
将_fetch
,因为get
没有返回任何内容。
要解决此问题,只需从_fetch
和get
方法返回async def get(url):
...
res = await self.fetch(url, method=method)
return res
对象即可。
此外,您并不真正需要async ... await
方法。您可以使用def get(url):
...
return self.fetch(url, method=method)
方法执行这些操作:
Observation month A/C num
2010-09 abc1
2010-10 abc1
2010-11 xyz
实际上,您甚至不需要{{1}}语法。这样可以正常工作:
{{1}}
为什么第二个代码示例可以正常工作,我将其留作练习让你弄明白。
答案 1 :(得分:0)
由于您已经使用其他详细信息更新了问题,并且它与原始版本有很大不同,我会添加另一个答案。
AsyncHTTPClient背后的魔力
考虑以下代码:
http_client = AsyncHTTPClient()
print(http_client.__class__)
# Output:
<class 'tornado.simple_httpclient.SimpleAsyncHTTPClient'>
如您所见,http_client
是SimpleAsyncHTTPClient
的实例,而不是AsyncHTTPClient
。那么,这里发生了什么?
如果查看https://en.wikipedia.org/wiki/Vigen%C3%A8re_cipher的源代码,您会看到它继承了tornado.utils.Configurable
类。
Configurable
类中最重要的一段代码是__new__
方法,它负责所有魔法。如果查看其AsyncHTTPClient
,您会发现它将创建类方法configurable_default
返回的任何类的实例。
现在,查看source code的源代码。它返回SimpleAsyncHTTPClient
类,这就是我们在上面创建的对象(http_client
)是SimpleAsyncHTTPClient
的实例,而不是AsyncHTTPClient
的实例。
最后,是的,您需要在子类中创建fetch_impl
方法。因为AsyncHTTPClient
会调用self.fetch_impl
方法。您可以在AsyncHTTPClient.configurable_default
中看到此信息。
虽然fetch_impl
类中尚未实现AsyncHTTPClient
,但它已在SimpleAsyncHTTPClient
中实施。你可以找到它this line in source code。
如何成功继承AsyncHTTPClient
?
我首先查看here并根据您的需要进行修改。