предисловие
Задокументируйте простой код для асинхронного программирования с помощью tornado, если вы читали мой предыдущий пост об asyncio.статьяВы обнаружите, что при использовании tornado и при использовании asyncio шаблон примерно одинаков. говорить легко, покажи код. Большая часть демо ниже взята изофициальная документация, частично изменен.
demo
1. Синхронный сетевой запрос
Первая демонстрация — это пример использования торнадо для синхронного программирования.Для сравнения с асинхронной версией ниже мы используем синхронный сетевой запрос, который поставляется с торнадо для тестирования. Пример очень простой и пояснять нечего, результат показывает, что используется функция обратного вызова, и функция обратного вызова будет вызвана после выполнения запроса, и будет выведен результат.
from tornado.httpclient import HTTPClient
from time import strftime
urls = [
'http://163.com',
'http://baidu.com'
]
def sync_fetch(url ,callback):
def handler_result(response):
callback(response)
http_client = HTTPClient()
http_client.fetch(url, callback=handler_result)
def sync_fetch_callback(response):
print(strftime('[%H:%M:%S]'),end=' ')
print('url:{} state:{} time:{}'.format(
response.request.url, response.code, response.request_time))
if __name__ == "__main__":
for url in urls:
sync_fetch(url, sync_fetch_callback)
выходной результат
[16:11:43] url:http://163.com state:200 time:0.15146231651306152
[16:11:43] url:http://baidu.com state:200 time:0.06663918495178223
2. Асинхронный сетевой запрос
Асинхронная версия демо ниже, использующая ту, которая поставляется с торнадо.AsyncHTTPClient,fetchМетод представляет собой функцию сопрограммы.Как и asyncio, функция сопрограммы должна использовать@gen.coroutineУкрасьте, используйте yield, чтобы дождаться возврата результата запроса. но не блокирует основной поток, гдеyield listБудет ждать элементы в списке параллельно.tornado.ioloop.IOLoop.current()получит текущий объект цикла событий,loop.run_sync(main)Цикл событий будет закрыт после завершения основного выполнения. Похож ли он на asyncio и есть ли он? Сравнивая с приведенными выше результатами вывода, можно обнаружить, что, поскольку доступ к baidu выполняется быстрее, результат доступа к baidu выводится первым.
import tornado
from tornado import gen
from time import strftime
from tornado.httpclient import AsyncHTTPClient
urls = [
'http://163.com',
'http://baidu.com'
]
def format_print(response):
print(strftime('[%H:%M:%S]'),end=' ')
print('url:{} state:{} time:{}'.format(
response.request.url, response.code, response.request_time))
@gen.coroutine
def async_fetch(url):
http_client = AsyncHTTPClient()
res = yield http_client.fetch(url)
format_print(res)
@gen.coroutine
def main():
yield [async_fetch(url) for url in urls]
if __name__ == '__main__':
loop = tornado.ioloop.IOLoop.current()
loop.run_sync(main)
выходной результат
[16:13:16] url:http://baidu.com state:200 time:0.06943202018737793
[16:13:16] url:http://163.com state:200 time:0.15732026100158691
Классическая демонстрация
Почему это классическая демонстрация, потому что в предыдущих демонстрациях в asyncio использовались блокирующие или неблокирующие функции сна для имитации реальных операций функций. Как и asyncio, tornado обеспечивает неблокирующую функцию сна.gen.sleep. Следующий пример в основном такой же, как и предыдущий пример в asyncio, поэтому он не будет объяснен.
from time import strftime
from tornado.ioloop import IOLoop
from tornado import gen
@gen.coroutine
def noblock_sleep(t):
print(strftime('[%H:%M:%S]'), end=' ')
print('func {} is running {}s'.format(t, t))
yield gen.sleep(t)
print(strftime('[%H:%M:%S]'), end=' ')
print('func {} is finished'.format(t))
@gen.coroutine
def main():
yield [noblock_sleep(t) for t in range(1,6)]
if __name__ == '__main__':
loop = IOLoop.current()
loop.run_sync(main)
выходной результат
[16:24:12] func 1 is running 1s
[16:24:12] func 2 is running 2s
[16:24:12] func 3 is running 3s
[16:24:12] func 4 is running 4s
[16:24:12] func 5 is running 5s
[16:24:13] func 1 is finished
[16:24:14] func 2 is finished
[16:24:15] func 3 is finished
[16:24:16] func 4 is finished
[16:24:17] func 5 is finished
Использование блокирующих функций в торнадо
Правильно, как и asyncio, торнадо обеспечиваетloop.run_in_executorВыполните операцию блокировки. Просто посмотрите на код напрямую, и я не буду вдаваться в подробности ниже.
from tornado import gen
from time import sleep, strftime
from concurrent.futures import ThreadPoolExecutor
from concurrent import futures
from tornado.ioloop import IOLoop
def blocked(t):
print(strftime('[%H:%M:%S]'), end=' ')
print('func {} is running {}s'.format(t, t))
sleep(t)
print(strftime('[%H:%M:%S]'), end=' ')
print('func {} is end'.format(t))
return t
@gen.coroutine
def main():
with ThreadPoolExecutor(max_workers=5) as executor:
loop = IOLoop.current()
results = yield [loop.run_in_executor(executor, blocked, t) for t in range(1,6)]
return results
if __name__ == '__main__':
loop = IOLoop.current()
results = loop.run_sync(main)
print('results:{}'.format(results))
выходной результат
[16:29:15] func 1 is running 1s
[16:29:15] func 2 is running 2s
[16:29:15] func 3 is running 3s
[16:29:15] func 4 is running 4s
[16:29:15] func 5 is running 5s
[16:29:16] func 1 is end
[16:29:17] func 2 is end
[16:29:18] func 3 is end
[16:29:19] func 4 is end
[16:29:20] func 5 is end
results:[1, 2, 3, 4, 5]
Наконец
Вот лишь краткий список некоторых кодов торнадо, а потом я начну пробовать читать исходники, в последнее время буду часто писать статьи и заставлять себя быть занятым.