使用select实现ioloop, 实现http请求异步,有利于理解select(epool)模型, 代码如下:
#!/bin/python
import select
import time
from http.client import HTTPConnection
class Handler(object):
pass
class AsyncHTTPHandler(Handler):
def __init__(self, url, io_loop, callback):
self.http_conn = HTTPConnection(url)
self.url = url
self.io_loop = io_loop
self.callback = callback
self.http_conn.connect()
self.fileno = self.http_conn.sock.fileno
print ("has conn:", self.http_conn, " fileno:", self.fileno())
self.can_recv = False
self.can_send = True
self.io_loop.add_handler(self)
def wants_recv(self):
return self.can_recv
def wants_send(self):
return self.can_send
def fileno(self):
return self.fileno
def handler_recv(self):
resp = self.res.read()
self.io_loop.remove_handler(self)
print ("Resp:",self.url,self.http_conn, self.res)
if self.callback:
callback(resp)
def handler_send(self):
print("Request:", self.url, self.http_conn)
self.http_conn.request("GET", "/", None, {})
self.res = self.http_conn.getresponse()
self.can_send = False
self.can_recv = True
class IOLoop(object):
handlers = []
def __init__(self):
pass
def event_loop():
handlers = IOLoop.handlers
while True:
r = [h for h in handlers if h.wants_recv()]
s = [h for h in handlers if h.wants_send()]
can_recv, can_send, err = select.select(r, s, [])
for h in can_recv:
h.handler_recv()
for h in can_send:
h.handler_send()
@staticmethod
def add_handler(h):
IOLoop.handlers.append(h)
@staticmethod
def remove_handler(h):
IOLoop.handlers.remove(h)
class AsyncHTTPClient(object):
"""
"""
def __init__(self, io_loop=None):
self.io_loop = io_loop or IOLoop
def fetch(self, url, io_loop=None, callback=None):
self.callback = callback
h = AsyncHTTPHandler(url, self.io_loop, callback)
# --- test code ---- #
def callback(r):
print("callback", r[:100])
def test():
http_client = AsyncHTTPClient()
t3 = time.time()
http_client.fetch("www.baidu.com", callback=callback)
http_client.fetch("www.python.org", callback=callback)
t4 = time.time()
print ("t4-t3", t4-t3)
#http_client.fetch("www.google.com", callback=callback)
IOLoop.event_loop()
print("==== loop start ====")
if __name__ == "__main__":
test()
打印:
has conn: <http.client.HTTPConnection object at 0x7faac8abd470> fileno: 3
has conn: <http.client.HTTPConnection object at 0x7faac82e2400> fileno: 4
t4-t3 0.13575148582458496
Request: www.baidu.com <http.client.HTTPConnection object at 0x7faac8abd470>
Request: www.python.org <http.client.HTTPConnection object at 0x7faac82e2400>
Resp: www.baidu.com <http.client.HTTPConnection object at 0x7faac8abd470> <http.client.HTTPResponse object at 0x7faac82e2780>
callback b'<!DOCTYPE html><!--STATUS OK-->\r\n<html>\r\n<head>\r\n\t<meta http-equiv="content-type" content="text/html'
Resp: www.python.org <http.client.HTTPConnection object at 0x7faac82e2400> <http.client.HTTPResponse object at 0x7faac82e2940>
callback b''