1. 异步基础概念 https://ruanyifeng.com/blog/2019/11/python-asyncio.html
    2. yield & yield from https://zhuanlan.zhihu.com/p/75347080
    3. yield & yield from https://www.jianshu.com/p/b036e6e97c18
    4. 异步入门 https://zhuanlan.zhihu.com/p/25228075
    5. asyncio 模块 https://mp.weixin.qq.com/s/JyhBVZPeKM5E44jrrA3LEA
    6. asyncio 模块 https://zhuanlan.zhihu.com/p/59621713
    7. async | await 关键字 https://zhuanlan.zhihu.com/p/27258289
    • 回调函数示例 ```python import socket import time

    from selectors import DefaultSelector, EVENT_WRITE, EVENT_READ

    selector = DefaultSelector() stopped = False urls = {‘/‘, ‘/1’, ‘/2’, ‘/3’, ‘/4’}

    class Crawler: def init(self, url, host): self.url = url self.host = host self.response = b’’ self.request = “GET {} HTTP/1.0\r\nHost: {}\r\n\r\n”.format(self.url, self.host)

    1. def fetch(self):
    2. self.sock = socket.socket()
    3. self.sock.setblocking(False)
    4. try:
    5. self.sock.connect((self.host, 80))
    6. except BlockingIOError:
    7. pass
    8. selector.register(self.sock.fileno(), EVENT_WRITE, self.on_connected)
    9. def on_connected(self, key, mask):
    10. selector.unregister(key.fd)
    11. print(f"Connected: {self.request.strip()}")
    12. self.sock.send(self.request.encode('ascii'))
    13. selector.register(key.fd, EVENT_READ, self.read_response)
    14. def read_response(self, key, mask):
    15. global stopped
    16. chunk = self.sock.recv(4096)
    17. while chunk:
    18. self.response += chunk
    19. chunk = self.sock.recv(4096)
    20. print(f"Finished: {self.request.strip()}")
    21. selector.unregister(key.fd)
    22. urls.remove(self.url)
    23. if not urls:
    24. stopped = True

    def loop(): while not stopped: events = selector.select() for event_key, event_mask in events: callback = event_key.data callback(event_key, event_mask)

    if name == ‘main‘: start = time.time() for url in urls: crawler = Crawler(url, “baidu.com”) crawler.fetch() loop() print(time.time() - start)

    1. > 可以在 `urls` 中只放一个元素,然后断点调试,观察程序流程
    2. - 生成器(yield)示例
    3. ```python
    4. import socket
    5. import time
    6. from selectors import DefaultSelector, EVENT_WRITE, EVENT_READ
    7. selector = DefaultSelector()
    8. urls = {'/', '/1', '/2', '/3', '/4'}
    9. stopped = False
    10. class Future:
    11. def __init__(self):
    12. self.result = None
    13. self._callbacks = []
    14. def add_done_callback(self, fn):
    15. self._callbacks.append(fn)
    16. def set_result(self, result):
    17. self.result = result
    18. for fn in self._callbacks:
    19. fn(self)
    20. class Crawler:
    21. def __init__(self, url, host):
    22. self.url = url
    23. self.host = host
    24. self.request = "GET {} HTTP/1.0\r\nHost: {}\r\n\r\n".format(self.url, self.host)
    25. self.response = b''
    26. def fetch(self):
    27. sock = socket.socket()
    28. sock.setblocking(False)
    29. try:
    30. sock.connect((self.host, 80))
    31. except BlockingIOError:
    32. pass
    33. f = Future()
    34. def on_connected():
    35. f.set_result(None)
    36. selector.register(sock.fileno(), EVENT_WRITE, on_connected)
    37. yield f
    38. selector.unregister(sock.fileno())
    39. print(f"Connected: {self.request.strip()}")
    40. sock.send(self.request.encode('ascii'))
    41. global stopped
    42. while True:
    43. f = Future()
    44. def on_readable():
    45. f.set_result(sock.recv(4096))
    46. selector.register(sock.fileno(), EVENT_READ, on_readable)
    47. chunk = yield f
    48. selector.unregister(sock.fileno())
    49. if chunk:
    50. self.response += chunk
    51. else:
    52. print(f"Finished: {self.request.strip()}")
    53. urls.remove(self.url)
    54. if not urls:
    55. stopped = True
    56. break
    57. class Task:
    58. def __init__(self, coro):
    59. self.coro = coro
    60. f = Future()
    61. self.step(f)
    62. def step(self, future):
    63. try:
    64. next_future = self.coro.send(future.result)
    65. except StopIteration:
    66. return
    67. next_future.add_done_callback(self.step)
    68. def loop():
    69. while not stopped:
    70. events = selector.select()
    71. for key, mask in events:
    72. callback = key.data
    73. callback()
    74. if __name__ == '__main__':
    75. start = time.time()
    76. for url in urls:
    77. crawler = Crawler(url, "baidu.com")
    78. Task(crawler.fetch())
    79. loop()
    80. print(time.time() - start)