tornado: httpclient & simple_httpclient

HTTPClient是httpclient.py中看到的第一个类。内容非常简单,但是却又没有看上去那么简单:

  1. fetch方法的实现会根据构造HTTPClient时传入的参数(async_client_class)发生变化。也就是说,HTTPClient并不是一个interface,而是一个delegator
  2. 每一个HTTPClient实例都会自己创建以及维护一个IOLoop。使用ioloop的目的,是为了实现异步的httprequest。这个ioloop会随着每一次fetch调用而start,request结束而stop,httpclient实例被销毁而close。
  3. 每一个HTTPClient会且只会对应一个async_client_class的实例。

在默认不传入任何参数的情况下,HTTPClient会选择AsyncHTTPClient作为默认的fetch engine。在tornado的注释里提到,HTTPClient只是为了方便使用,绝大多数情况下,application应该直接使用AsyncHTTPClient(可别搞混了,两者名字很像但根本不是继承关系)

AsyncHTTPClient理论上讲是一个abstract class,因为最重要的fetch方法,它并没有实现,而是依赖于子类(例如SimpleAsyncHTTPClient)的实现。AsyncHTTPClient重载了__new__方法,导致AsyncHTTPClient的对象创建过程显现出一种难以言语的诡异行为:

  1. 如果采用默认参数构造AsyncHTTPClient,得到的是一个SimpleAsyncHTTPClient对象的实例
  2. 如果在构造AsyncHTTPClient之前调用过AsyncHTTPClient.configure方法,可能会得到完全不同的另一个对象,例如AsyncHTTPClient.configure(async_client_class=CurlAsyncHTTPClient)
  3. 如果构造AsyncHTTPClient时全部使用默认参数,则每次得到的都是同一个对象的实例(如果此对象还没有在其他地方被析构删除)
  4. 如果构造AsyncHTTPClient时使用如下参数列表:force_instance=True,则每次得到的都是不同对象的实例。
  5. 如果构造AsyncHTTPClient时时每次传入不同的ioloop的实例,例如AsyncHTTPClient(IOLoop()),则不论是否设置force_instance=True,每次得到的也都是不同的实例。。。

根据上面的行为,得到两条结论:

  1. 一个AsyncHTTPClient(及其子孙类)的实例,对应且只能对应一个IOLoop;
  2. AsyncHTTPClient是一个可以实例化的有工厂的行为的“抽象类”(可以通过调用configure方法定义工厂的行为);

在tornado的注释中提到,对于SimpleAsyncHTTPClient,”It is intended to become the default AsyncHTTPClient implementation in a future release“。这个类非常简单木有啥好说的,只有三点有必要提一下:

  1. 这是一个实现了fetch方法的哥们
  2. 它继承自AsyncHTTPClient
  3. 它接受一个参数max_clients。别被它的名字弄糊涂了,这不是the maximum of clients,而是当前client实例的the maximum number of parall asynchronize fetch call!

稍微总结一下:

  • HTTPClient是一个为了使用方便而定义的帮助类,提供的默认的callback方法会自动在每次fetch结束后清理资源。
  • AsyncHTTPClient是一个”抽象类“
  • SimpleAsyncHTTPClient和CurlAsyncHTTPClient是AsyncHTTPClient的子类,在直接使用这两个类的时候需要显示的制定Http请求的callback方法。

相关推荐