博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

用tornado 写异步回调程序

Posted on 2014-12-30 22:57  david2303  阅读(840)  评论(0编辑  收藏  举报

用tornado,一般都用到它的 AsyncHTTPClient的 fetch。我们可以参考 fetch,使用tornado的特性,写异步回调程序

 

首先看看 fetch的实现,关键是用了future

def fetch(self, request, callback=None, **kwargs):
        """Executes a request, asynchronously returning an `HTTPResponse`.

        The request may be either a string URL or an `HTTPRequest` object.
        If it is a string, we construct an `HTTPRequest` using any additional
        kwargs: ``HTTPRequest(request, **kwargs)``

        This method returns a `.Future` whose result is an
        `HTTPResponse`.  The ``Future`` wil raise an `HTTPError` if
        the request returned a non-200 response code.

        If a ``callback`` is given, it will be invoked with the `HTTPResponse`.
        In the callback interface, `HTTPError` is not automatically raised.
        Instead, you must check the response's ``error`` attribute or
        call its `~HTTPResponse.rethrow` method.
        """
        if not isinstance(request, HTTPRequest):
            request = HTTPRequest(url=request, **kwargs)
        # We may modify this (to add Host, Accept-Encoding, etc),
        # so make sure we don't modify the caller's object.  This is also
        # where normal dicts get converted to HTTPHeaders objects.
        request.headers = httputil.HTTPHeaders(request.headers)
        request = _RequestProxy(request, self.defaults)
        future = TracebackFuture()
        if callback is not None:
            callback = stack_context.wrap(callback)

            def handle_future(future):
                exc = future.exception()
                if isinstance(exc, HTTPError) and exc.response is not None:
                    response = exc.response
                elif exc is not None:
                    response = HTTPResponse(
                        request, 599, error=exc,
                        request_time=time.time() - request.start_time)
                else:
                    response = future.result()
                self.io_loop.add_callback(callback, response)
            future.add_done_callback(handle_future)

        def handle_response(response):
            if response.error:
                future.set_exception(response.error)
            else:
                future.set_result(response)
        self.fetch_impl(request, handle_response)
        return future

 

所以,只要用了future,我们也可以写异步代码

def test(callback=None):
    future = TracebackFuture()
    if callback is not None:
        callback = stack_context.wrap(callback)

        def handle_future(future):
            response = future.result()
            IOLoop.current().add_callback(callback, response)
        future.add_done_callback(handle_future)

    def handle_response(response=''):
        future.set_result(response)

    test_func(handle_response)

    return future

test_func里面,我就把函数handle_response传出去了,只要后续的操作,调用了handle_response,就会回调 函数handle_future,最后回调 函数callback