python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Python协程数据库读写加速?peewee-async异步MySQL

Python协程数据库读写怎么加速?peewee-async异步MySQL实战

作者:XerCis

还在为数据库读写速度发愁吗?本文带你了解如何用peewee-async库在单线程内通过协程和IO多路复用实现并发,让MySQL查询显著加快,基于aiomysql驱动,从安装、异步读写、事务到速度测试,一应俱全,还贴心总结了异步可能变慢的坑,助你避雷

简介

协程可以在单线程内实现并发,原理是循环和 IO 多路复用,使用协程可以让数据库读取加快

peewee-async 底层基于 aiomysql

本文以 MySQL 为例

安装

pip install peewee-async

不同数据库连接驱动

pip install aiomysql

初试

使用本机连接,创建数据库 test

import asyncio
import peewee_async
from peewee import *

database = peewee_async.MySQLDatabase('test', user='root', password='123456', host='127.0.0.1', port=3306)


class TestModel(Model):
    text = CharField()

    class Meta:
        database = database


# 同步
TestModel.create_table(True)
TestModel.create(text='Yo, I can do it sync!')
database.close()

# 异步
objects = peewee_async.Manager(database)
database.set_allow_sync(False)


async def handler():
    await objects.create(TestModel, text='Not bad. Watch this, I am async!')
    all_objects = await objects.execute(TestModel.select())
    for obj in all_objects:
        print(obj.text)


loop = asyncio.get_event_loop()
loop.run_until_complete(handler())
loop.close()

# 以同步方式删除表
with objects.allow_sync():
    TestModel.drop_table(True)

异步读写

import asyncio

from peewee import Model, CharField, TextField
from peewee_async import MySQLDatabase, Manager

loop = asyncio.new_event_loop()
database = MySQLDatabase('test', user='root', password='123456', host='127.0.0.1', port=3306)
objects = Manager(database, loop=loop)


class PageBlock(Model):
    key = CharField(max_length=40, unique=True)
    text = TextField(default='')

    class Meta:
        database = database


PageBlock.create_table(True)
objects.database.allow_sync = False


async def my_async_func():
    await objects.create_or_get(PageBlock, key='title', text='Peewee is AWESOME with async!')

    title = await objects.get(PageBlock, key='title')
    print('Was:', title.text)

    title.text = 'Peewee is SUPER awesome with async!'
    await objects.update(title)
    print('New:', title.text)


loop.run_until_complete(my_async_func())
loop.close()
# Was: Peewee is AWESOME with async!
# New: Peewee is SUPER awesome with async!

同时使用同步和异步调用

import asyncio

import peewee_async
from peewee import Model, CharField

database = peewee_async.MySQLDatabase('test', user='root', password='123456', host='127.0.0.1', port=3306)
loop = asyncio.get_event_loop()


class TestModel(Model):
    text = CharField()

    class Meta:
        database = database


# 同步
TestModel.create_table(True)
database.close()


@asyncio.coroutine
def my_handler():
    obj1 = TestModel.create(text='Yo, I can do it sync!')
    obj2 = yield from peewee_async.create_object(TestModel, text='Not bad. Watch this, I am async!')

    all_objects = yield from peewee_async.execute(TestModel.select())
    for obj in all_objects:
        print(obj.text)

    obj1.delete_instance()
    yield from peewee_async.delete_object(obj2)


loop.run_until_complete(database.connect_async(loop=loop))
loop.run_until_complete(my_handler())

事务

import asyncio

import peewee_async
from peewee import Model, CharField

database = peewee_async.MySQLDatabase('test', user='root', password='123456', host='127.0.0.1', port=3306)
loop = asyncio.get_event_loop()


class TestModel(Model):
    text = CharField()

    class Meta:
        database = database


# 同步
TestModel.create_table(True)
database.close()


async def test():
    obj = await peewee_async.create_object(TestModel, text='FOO')
    obj_id = obj.id

    try:
        async with database.atomic_async():
            obj.text = 'BAR'
            await peewee_async.update_object(obj)
            raise Exception('Fake error')
    except:
        res = await peewee_async.get_object(TestModel, TestModel.id == obj_id)
        print(res.text)


loop.run_until_complete(test())
# FOO

速度测试

安装

pip install faker

代码

import time
import asyncio

import peewee_async
from peewee import *
from faker import Faker

database = peewee_async.MySQLDatabase('test', user='root', password='123456', host='127.0.0.1', port=3306)


class Student(Model):
    id = PrimaryKeyField()
    name = CharField()
    birthday = DateField()
    chinese = IntegerField()
    math = IntegerField()
    english = IntegerField()

    class Meta:
        database = database


Student.create_table(True)

# 数据准备
faker = Faker('zh_CN')
students = []
batch_size = 100
for _ in range(100000):  # 10w条数据
    student = Student(name=faker.name(), birthday=faker.date(), chinese=faker.random_int(min=0, max=100),
                      math=faker.random_int(min=0, max=100), english=faker.random_int(min=0, max=100))
    students.append(student)
    if len(students) >= batch_size:
        Student.bulk_create(students, batch_size=batch_size)
        students.clear()
print('数据准备完成')


def sync_read():
    """同步读取"""
    begin = time.time()
    students1 = Student.select().where(Student.birthday >= '2000-01-01')
    students2 = Student.select().where(Student.chinese >= 70)
    students3 = Student.select().where(Student.math >= 80)
    students4 = Student.select().where(Student.english >= 90)
    lengths = len(students1), len(students2), len(students3), len(students4)
    print('sync_read: {:.2f}s'.format(time.time() - begin))
    return lengths


async def async_read():
    """异步读取"""
    begin = time.time()
    students1 = await manager.execute(Student.select().where(Student.birthday >= '2000-01-01'))
    students2 = await manager.execute(Student.select().where(Student.chinese >= 70))
    students3 = await manager.execute(Student.select().where(Student.math >= 80))
    students4 = await manager.execute(Student.select().where(Student.english >= 90))
    lengths = len(students1), len(students2), len(students3), len(students4)
    print('async_read: {:.2f}s'.format(time.time() - begin))
    return lengths


if __name__ == '__main__':
    sync_read()

    manager = peewee_async.Manager(database)
    database.set_allow_sync(False)
    loop = asyncio.get_event_loop()
    loop.run_until_complete(async_read())
    # 数据准备完成
    # sync_read: 3.10s
    # async_read: 1.86s

遇到的坑

异步某些情况可能会慢些

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文