[PYTHON] Ich habe versucht, aiomysql zu verwenden

Bei PyConJP2016 habe ich erfahren, dass Python in letzter Zeit [asyncio] enthält (http://docs.python.jp/3/library/asyncio.html). Ich habe verstanden, dass Asyncio es ermöglicht, die Wartezeit effizient zu nutzen, wenn die Wartezeit im Programm auftritt, wie z. B. die E / A-Verarbeitung (wahrscheinlich), und dachte daher, dass damit die Abfrage an MySQL beschleunigt werden kann. Weitere Informationen zu Asyncio finden Sie in anderen Artikeln. Als MySQL eine Abfrage ausführen ließ, untersuchte ich, ob es einen Unterschied in der Verarbeitungszeit zwischen der Verwendung einer Bibliothek, die Asyncio unterstützt, und der Nichtverwendung gibt. Verwenden Sie aiomysql als Bibliothek für die Verbindung zu MySQL, das Asyncio unterstützt. aiomysql scheint eine auf PyMySQL basierende Bibliothek zu sein, aber da ursprünglich MySQL-Connector-Python verwendet wurde, ist das Vergleichsziel MySQL-Connector-Python.

Fazit

Zusammenfassend gab es keinen großen Unterschied in der Verarbeitungszeit zwischen aiomysql und MySQL-Connector-Python .... Mache ich mit Asyncio einen Fehler in der Situation? Ist es in einem Schloss in MySQL stecken geblieben?

Dieses Ergebnis lässt nicht den Schluss zu, dass aiomysql langsam ist, sondern zeigt nur, dass räumliche Abfragen nicht schneller werden (obwohl diese SELECT-Abfrage auch schneller wird, wenn sie in mehreren Prozessen parallelisiert wird ...).

Datenbankseite

Ich führe SQL mit dem Spatial Index von MySQL aus. Die Tabelle, die ich verwendet habe, ist wie folgt. Diese Tabelle enthält die Grenzpolygondaten [1] japanischer Städte, Gemeinden, Städte und Dörfer.

create table if not exists {TABLE} ( 
    code mediumint(5) not null, 
    name varchar(100) not null, 
    shape multipolygon not null, 
    center point, 
    primary key (code), 
    spatial key shape (shape) 
) engine=MyISAM default charset=utf8;

Die Abfrage, die ich ausgeführt habe, lautet:

select code from {TABLE} 
    where st_contains(shape, geomfromtext(%s))

Programm verwendet

Ein Programm, das eine TSV-Datei mit Breiten- und Längengraden liest und einen übereinstimmenden Bereich ausgibt.

Programme, die aiomysql verwenden

asyncmatcher.py


# coding: utf-8

import sys
import csv
csv.field_size_limit(10000000000)
import asyncio
import aiomysql

TABLE = 'gxmlcity'
contains_sql = ('SELECT code from {table} '
                'WHERE St_Contains(shape, GeomFromText(%s))').format(table=TABLE)


import time
def record_time(func):
    def record(*args, **kwargs):
        start = time.time()
        ret = func(*args, **kwargs)
        elapsed_time = time.time() - start
        print('Elapsed time: {} [sec]'.format(elapsed_time), file=sys.stderr)
    return record


def print_result(cols, result):
    if result:
        print(*(tuple(cols) + result[0]), sep='\t')
    else:
        print(*(tuple(cols) + ('No Match',)), sep='\t')
    if len(result) > 1:
        print(cols, result)

async def match(cur, lat, lon):
    p_str = 'POINT({} {})'.format(lat, lon)
    await cur.execute(contains_sql, (p_str,))
    result = await cur.fetchall()
    return result

async def iterate_to_match(cur, args):
    for cols in csv.reader(args.infile, delimiter='\t'):
        if cols[2] != 'None':
            result = await match(cur, float(cols[2]), float(cols[3]))
            print_result(cols, result)

async def match_areas(loop, args):
    conn = await aiomysql.connect(user='root', password='', db=args.dbname, loop=loop, charset='utf8')
    try:
        cur = await conn.cursor()
        await iterate_to_match(cur, args)
        await cur.close()
    finally:
        conn.close()


def parse_args():
    import argparse
    parser = argparse.ArgumentParser(description='Asynchrone Bereichsanpassung')
    parser.add_argument('--infile', type=argparse.FileType('r', encoding='utf-8'), default=sys.stdin)
    parser.add_argument('--dbname', required=True, help='DB-Name mit Bereich DB')
    return parser.parse_args()

@record_time
def main():
    loop = asyncio.get_event_loop()
    loop.run_until_complete(match_areas(loop, args))
    loop.close()

if __name__ == '__main__':
    args = parse_args()
    main()

Programme, die mysql-connector-python verwenden

singlematcher.py


# coding: utf-8

import sys
import csv
csv.field_size_limit(10000000000)
import mysql.connector


TABLE = 'gxmlcity'
contains_sql = ('SELECT code from {table} '
                'WHERE St_Contains(shape, GeomFromText(%s))').format(table=TABLE)


import time
def record_time(func):
    def record(*args, **kwargs):
        start = time.time()
        ret = func(*args, **kwargs)
        elapsed_time = time.time() - start
        print('Elapsed time: {} [sec]'.format(elapsed_time), file=sys.stderr)
    return record


def print_result(cols, result):
    if result:
        print(*(tuple(cols) + result[0]), sep='\t')
    else:
        print(*(tuple(cols) + ('No Match',)), sep='\t')
    if len(result) > 1:
        print(cols, result)

def match(cur, lat, lon):
    p_str = 'POINT({} {})'.format(lat, lon)
    cur.execute(contains_sql, (p_str,))
    result = cur.fetchall()
    return result

def iterate_to_match(cur, args):
    for cols in csv.reader(args.infile, delimiter='\t'):
        if cols[2] != 'None':
            result = match(cur, float(cols[2]), float(cols[3]))
            print_result(cols, result)

def match_areas(args):
    conn = mysql.connector.connect(user='root', password='', db=args.dbname, charset='utf8')
    try:
        cur = conn.cursor()
        iterate_to_match(cur, args)
        cur.close()
    finally:
        conn.close()


def parse_args():
    import argparse
    parser = argparse.ArgumentParser(description='Der Bereichsabgleich wird normalerweise durchgeführt')
    parser.add_argument('--infile', type=argparse.FileType('r', encoding='utf-8'), default=sys.stdin)
    parser.add_argument('--dbname', required=True, help='DB-Name mit Bereich DB')
    return parser.parse_args()

@record_time
def main():
    match_areas(args)

if __name__ == '__main__':
    args = parse_args()
    main()

Vergleich

Bei Verwendung von aiomysql (diejenigen, die parallel anfordern möchten)

time ( gzip -dc json_2014-08-01.txt.gz | head -n 1000 | python scripts/asyncmatcher.py --dbname reftest > /dev/null )
Elapsed time: 29.44952368736267 [sec]

real    0m29.581s
user    0m0.736s
sys     0m0.044s

Bei Verwendung von MySQL-Connector-Python (normalerweise)

$ time ( gzip -dc json_2014-08-01.txt.gz | head -n 1000 | python scripts/singlematcher.py --dbname reftest > /dev/null )
Elapsed time: 27.986697673797607 [sec]

real    0m28.183s
user    0m0.620s
sys     0m0.024s

Zusammenfassung

Selbst wenn ich Asyncio benutze, wird es nicht schneller ... Ist dies die richtige Situation?

Experimentierumgebung

Ich vergleiche, aber die Python-Version ist anders. MySQL-Connector-Python war nicht mit Python 3.5 kompatibel.

MySQL-Connector-Bei Verwendung von Python

Bei Verwendung von aiomysql

Verweise

[1] Taihei Morikuni, Mitsuo Yoshida, Masayuki Okabe, Kyoji Umemura. Wortfiltermethode zur Schätzung der Position von Tweet-Postings. Journal of the Information Processing Society. 2015, Bd. 8, Nr. 4, S. 16–26.

Recommended Posts

Ich habe versucht, aiomysql zu verwenden
Ich habe versucht, parametrisiert zu verwenden
Ich habe versucht, Argparse zu verwenden
Ich habe versucht, Mimesis zu verwenden
Ich habe versucht, anytree zu verwenden
Ich habe versucht, Summpy zu verwenden
Ich habe versucht, Coturn zu verwenden
Ich habe versucht, Pipenv zu verwenden
Ich habe versucht, Matplotlib zu verwenden
Ich habe versucht, "Anvil" zu verwenden.
Ich habe versucht, Hubot zu verwenden
Ich habe versucht, ESPCN zu verwenden
Ich habe versucht, openpyxl zu verwenden
Ich habe versucht, Ipython zu verwenden
Ich habe versucht, PyCaret zu verwenden
Ich habe versucht, Cron zu verwenden
Ich habe versucht, ngrok zu verwenden
Ich habe versucht, face_recognition zu verwenden
Ich habe versucht, Jupyter zu verwenden
Ich habe versucht, doctest zu verwenden
Ich habe versucht, Folium zu verwenden
Ich habe versucht, jinja2 zu verwenden
Ich habe versucht, Folium zu verwenden
Ich habe versucht, das Zeitfenster zu verwenden
[Ich habe versucht, Pythonista 3 zu verwenden] Einführung
Ich habe versucht, easydict (Memo) zu verwenden.
Ich habe versucht, das Gesicht mit Face ++ zu erkennen
Ich habe versucht, RandomForest zu verwenden
Ich habe versucht, BigQuery ML zu verwenden
Ich habe versucht, Amazon Glacier zu verwenden
Ich habe versucht, Git Inspector zu verwenden
Ich habe versucht, Magenta / TensorFlow zu verwenden
Ich habe versucht, AWS Chalice zu verwenden
Ich habe versucht, Slack Emojinator zu verwenden
Ich habe versucht, Rotrics Dex Arm # 2 zu verwenden
Ich habe versucht, Rotrics Dex Arm zu verwenden
Ich habe versucht, GrabCut von OpenCV zu verwenden
Ich habe versucht, Thonny (Python / IDE) zu verwenden.
Ich habe versucht, mit dem Server-Client über tmux zu kommunizieren
Ich habe versucht, mit PyBrain verstärkt zu lernen
Ich habe versucht, mit Theano tief zu lernen
Ich habe irgendwie versucht, ein Jupyter-Notebook zu verwenden
[Kaggle] Ich habe versucht, mit unausgeglichenem Lernen zu unterabtasten
Ich habe versucht, mit OpenPose eine Schildkrötenwelle zu schießen
Ich habe versucht, die checkio-API zu verwenden
Ich habe versucht, asynchrone Verarbeitung mit Asyncio
Ich habe versucht zu kratzen
Ich habe PyQ ausprobiert
Ich habe AutoKeras ausprobiert
Ich habe es mit Papiermühle versucht
Ich habe versucht, Django-Slack
Ich habe es mit Django versucht
Ich habe es mit Spleeter versucht
Ich habe es mit cgo versucht
Ich habe versucht, Amazon SQS mit Django-Sellerie zu verwenden
Ich habe versucht, ○ ✕ mit TensorFlow zu spielen
Ich habe versucht, YOUTUBE Data API V3 zu verwenden