Skip to content

Instantly share code, notes, and snippets.

@alex8224
Last active December 23, 2015 03:24
Show Gist options
  • Save alex8224/6fa0a1758485b93b37fd to your computer and use it in GitHub Desktop.
Save alex8224/6fa0a1758485b93b37fd to your computer and use it in GitHub Desktop.
call async io function in coroutine
# -*- coding:utf-8 -*-
from tornado.gen import coroutine
from tornado.concurrent import Future
from tornado.ioloop import IOLoop
from tornado.httpclient import AsyncHTTPClient
from functools import wraps, partial
ioloop = IOLoop.instance()
AsyncHTTPClient.configure("tornado.curl_httpclient.CurlAsyncHTTPClient")
httpclient = AsyncHTTPClient()
class Return(Exception):
def __init__(self, value):
super(Return, self).__init__()
self._value = value
@property
def value(self):
return self._value
def subcoroutine(func):
final_future = Future()
def _continue_yield(result, future):
try:
tmp_result = result.send(future.result())
if isinstance(tmp_result, Future):
ioloop.add_callback(_io_callback, result, tmp_result)
else:
raise Exception("only support yield future")
except StopIteration:
final_future.set_result(None)
except Return as rvalue:
final_future.set_result(rvalue.value)
except Exception as ex:
final_future.set_exception(ex)
def _io_callback(result, attach=None):
if isinstance(attach, Future):
ioloop.add_future(attach, partial(_continue_yield, result))
@wraps(func)
def inner_call(*args, **kwargs):
result = func(*args, **kwargs)
attach = result.send(None)
ioloop.add_callback(_io_callback, result, attach)
return final_future
return inner_call
@subcoroutine
def step1(url):
print("step1, fetch %s url" % url)
response = yield httpclient.fetch(url)
print("step1, fetch %s url ok , http code is:%d" % (url, response.code))
raise Return(response)
@subcoroutine
def step2(url):
print("fetch %s" % url)
response = yield httpclient.fetch(url)
print("%s url fetch ok, the http code is:%d" % (url, response.code))
raise Return(response)
@subcoroutine
def call_other_coroutine(url, url2):
response = yield httpclient.fetch(url)
print("%s fetch ok" % url)
yield step2(url2)
print("%s fetch ok" % url2)
@coroutine
def start():
response = yield step1("https://www.baidu.com")
print("https://www.yahoo.com", response.headers)
response = yield step2("http://www.baidu.com")
print("http://www.apple.com", response.headers)
yield call_other_coroutine("https://news.ycombinator.com/", "http://www.quora.com")
ioloop.run_sync(start)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment