Wie man Async damit benutzt, kann ab Python 3.5 verwendet werden. PEP 492 -- Coroutines with async and await syntax
async with? Eine asynchrone Version des Kontextmanagers.
Wenn es Verarbeitung wie gibt
async with MyDB() as db:
db.do_something()
Wenn Sie MyDB durch Ausführen des Codes verbessern, können Sie die Datenbankverbindung automatisch schließen, wenn Sie die asynchrone Verbindung mit block beenden.
Erstellen wir beispielsweise eine Klasse, die aiomysql umschließt, und verwenden Sie sie.
my_db.py
my_db.py
import asyncio
import aiomysql
class MyDB:
#Wird kurz vor der Eingabe von async mit aufgerufen.
async def __aenter__(self):
loop = asyncio.get_event_loop()
self._connection = await aiomysql.connect(
host='localhost',
port=3306,
user='root',
password='ultrastrongpassword',
db='my_db',
charset='utf8',
loop=loop
)
return self
#Wird sofort nach dem Beenden des Async mit Block aufgerufen.
async def __aexit__(self, exc_type, exc, tb):
self._connection.close()
async def fetchall(self, query, args=[]):
cursor = await self._connection.cursor()
await cursor.execute(query, args)
return await cursor.fetchall()
Es fühlt sich an, als würde man das Verbindungsziel von aiomysql verstecken.
Die wichtigsten sind "aenter" und "aexit". Durch die Implementierung dieser kann diese Klasse als asynchroner Kontextmanager verwendet werden. Der Zeitpunkt des Anrufs ist wie kommentiert.
Wie im Beispiel ist aenter ein gängiges Muster zum Einrichten von Ressourcen und aexit zum Freigeben von Ressourcen.
Schauen wir uns auch den Anrufer an.
Seite zu verwenden
from my_db import MyDB
class Hoge:
async def call_db(self):
# db = MyDB()
# async with db:
#Aber es hat die gleiche Bedeutung.
async with MyDB() as db:
result = db.fetchall('select * from some_table')
print(result)
Das Format ist "asynchron mit [asynchroner Kontextmanager-Instanz] als [Rückgabewert von __aenter __]:".
Wenn dies ausgeführt wird, wird die Verarbeitung in der folgenden Reihenfolge fortgesetzt.
__init__
wird aufgerufen)__aenter__
wird aufgerufen__aenter__
von MyDB wird in db von async mit as db
gespeichertresult = db.fetchall ('select * from some_table')
wird ausgeführt__aexit__
wird aufgerufenEs scheint, dass eine Datenbankinstanz nur dann alle Ressourcen nutzen kann, wenn sie asynchron ist.
Wenn Sie so etwas wie "asynchron mit MyDB.connect () als db:" ausführen möchten
Seite zu verwenden
class Hoge:
async def call_db(self):
async with MyDB.connect() as db:
result = db.fetchall('select * from some_table')
print(result)
Implementieren Sie die Verbindungsmethode einfach wie folgt:
my_db.py
class MyDB:
__slots__ = ['_connection']
async def __aenter__(self):
(Abkürzung)
async def __aexit__(self, exc_type, exc, tb):
self._connection.close()
async def fetchall(self, query, args=[]):
(Abkürzung)
@classmethod
def connect(cls):
return cls()
Sie benötigen lediglich eine Instanz von MyDB (Asynchronous Context Manager) nach der Asynchronisierung mit.
Seite zu verwenden
class Hoge:
async def call_db(self):
async with MyDB.direct_fetch('select * from some_table') as rows:
print(rows)
In diesem Fall ist es unwahrscheinlich, dass sich der Rückgabewert von MyDB.direct_fetch in asynchroner Form mit in der MyDB-Instanz befindet. Sie müssen also ein wenig nachdenken. Get aiohttp kann hilfreich sein.
Sie können dies tun, indem Sie eine private Kontextmanagerklasse wie unten gezeigt erstellen.
my_db.py
class _QueryContextManager:
def __init__(self, coro):
self._coro = coro
async def __aenter__(self):
loop = asyncio.get_event_loop()
self._connection = await aiomysql.connect(
host='localhost',
port=3306,
user='root',
password='ultrastrongpassword',
db='my_db',
charset='utf8',
loop=loop
)
return await self._coro(self._connection)
async def __aexit__(self, exc_type, exc, tb):
self._connection.close()
class MyDB:
__slots__ = ['_connection']
@classmethod
def direct_fetch(cls, query, args=[]):
async def fetch(connection):
cursor = await connection.cursor()
await cursor.execute(query, args)
return await cursor.fetchall()
#Gibt einen privaten Kontextmanager zurück.
return _QueryContextManager(coro=fetch)
Hmm. Ich kann das Gefühl der Gewalt nicht leugnen. .. Es gibt vielleicht einen besseren Weg, es zu schreiben.
aiohttp kann die Verbindung von der Instanz des Rückgabewerts der Anforderung (self._resp.release ()) schließen, sodass sie etwas sauberer zu sein scheint.
Recommended Posts