Это достаточно вольный перевод статьи об основных новшествах асинхронного драйвера для
mongodb
используемого в tornado
. Основной мотив, который послужил для написания этого перевода — новшества, появившиеся в этой версии, такие как поддержка asyncio
, async
, await
и Python 3.5
. Сама статья не сколько перечисление новшеств, сколько лаконичные примеры асинхронной работы с MongoDB
.Введение
asyncio
aggregate
Python 3.5
async and await
Введение
Недавно была опубликована новая
Beta
версия Python
драйвера для Mongodb
, Motor
. В этой версии содержится одно из самых больших обновлений. Для установки можно использовать:python -m pip install --pre motor==0.5b0
Motor 0.5
по прежнему зависит от PyMongo 2.8.0
. Это устаревшая версия PyMongo
, но сейчас не было достаточно времени чтоб полностью перейти на третью версию, что простительно, так как этот релиз достаточно большой.
asyncio
Motor
теперь может интегрироваться с asyncio
, как альтернатива Tornado
. Большая благодарность Реми Джолину, Андрею Светлову svetlov и Николаю Новику за их огромный вклад в интеграцию Motor
для работы с asyncio
.
API-Интерфейсы Tornado
и asyncio
являются родственными. Пример Motor
с Tornado
:
# Tornado API
from tornado import gen, ioloop
from motor.motor_tornado import MotorClient
@gen.coroutine
def f():
result = yield client.db.collection.insert({'_id': 1})
print(result)
client = MotorClient()
ioloop.IOLoop.current().run_sync(f)
И здесь пример для asyncio:
import asyncio
from motor.motor_asyncio import AsyncIOMotorClient
@asyncio.coroutine
def f():
result = yield from client.db.collection.insert({'_id': 1})
print(result)
client = AsyncIOMotorClient()
asyncio.get_event_loop().run_until_complete(f())
В отличие от
Tornado
, asyncio
не включает реализацию http
, а тем более не является фреймворком. Для этого используйте библиотеку aiohttp
Андрея Светлова. Небольшой пример для работы Motor с aiohttp.
aggregate
MotorCollection.aggregate теперь по умолчанию возвращает курсор, и курсор возвращается непосредственно без
yield
. Старый синтаксис больше не поддерживается:
# Motor 0.4 and older, no longer supported.
cursor = yield collection.aggregate(pipeline, cursor={})
while (yield cursor.fetch_next):
doc = cursor.next_object()
print(doc)
В
Motor 0.5
просто сделайте:
# Motor 0.5: no "cursor={}", no "yield".
cursor = collection.aggregate(pipeline)
while (yield cursor.fetch_next):
doc = cursor.next_object()
print(doc)
В
asyncio
для этого используется yield from
:
# Motor 0.5 with asyncio.
cursor = collection.aggregate(pipeline)
while (yield from cursor.fetch_next):
doc = cursor.next_object()
print(doc)
Python 3.5
Сейчас
Motor
совместим с Python 3.5
, что потребовало определённых усилий. Это было трудно, потому что Motor
не просто работает с сопрограммами (coroutines), он использует сопрограммы внутри себя для реализации некоторых из своих функций, таких как MotorClient.open и MotorGridFS.put.Был метод для написания сопрограмм, которые работают в
Python 2.6
c Python 3.4
, но в Python 3.5
это было окончательно поломано. Нет единого пути для возвращения значений из Python 3.5
нативной сопрограмме или Python 2
генератора базирующегося на сопрограмме, так что все внутренние сопрограммы motor
, которые возвращают значения, были переписаны с помощью обратных вызовов.
async and await
Награда за усилия потраченные на интеграцию с
Python 3.5
, состоит в том что теперь motor
работает с родной сопрограммой, написанной с учетом ключевых слов async
и await
синтаксис:
async def f():
await collection.insert({'_id': 1})
Курсор из MotorCollection.find, MotorCollection.aggregate, или MotorGridFS.find может быть красиво и очень эффективно итегрирован в нативных сопрограммах (coroutines) с
async for
:
async def f():
async for doc in collection.find():
print(doc)
Насколько эффективно? Для коллекции из 10 000 документов этот пример кода выполнялся за 0.14 секунды.
# Motor 0.5 with Tornado.
@gen.coroutine
def f():
cursor = collection.find()
while (yield cursor.fetch_next):
doc = cursor.next_object()
print(doc)
Следующий код, в котором просто заменены gen.coroutine
и yield
на async
и await
и выполняет примерно тоже.
# Motor 0.5 with Tornado, using async and await.
async def f():
cursor = collection.find()
while (await cursor.fetch_next):
doc = cursor.next_object()
print(doc)
Но с
async for
время работы занимает 0.04 секунды, то есть в три раза быстрее.
# Motor 0.5 with Tornado, using async for.
async def f():
cursor = collection.find()
async for doc in cursor:
print(doc)
Однако, MotorCursor в to_list прежнему играет основную роль:
# Motor 0.5 with Tornado, using to_list.
async def f():
cursor = collection.find()
docs = await cursor.to_list(length=100)
while docs:
for doc in docs:
print(doc)
docs = await cursor.to_list(length=100)
Функция с
to_list
в два раза быстрее чем асинхронные, но это выглядит не так красиво и требует указания размера чанка. Я думаю, что async for
выглядит довольно стильно и работает достаточно быстро для того, чтобы его применять в большинстве случаев.
Бета версии релизов motor
публиковались далеко не всегда, но в этот раз по-другому. Интеграция asyncio
в motor
является совершенно новой. И поскольку это потребовало повсеместного рефакторинга ядра motor
, и переписывания существующей интеграции tornado
, была выпущена бета-версия для того, чтобы исправить все упущения.
P.S. Просьба о грамматических ошибках и ошибках перевода писать в личку.
This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.
Комментариев нет:
Отправить комментарий