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.
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 ...).
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))
Ein Programm, das eine TSV-Datei mit Breiten- und Längengraden liest und einen übereinstimmenden Bereich ausgibt.
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()
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()
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
Selbst wenn ich Asyncio benutze, wird es nicht schneller ... Ist dies die richtige Situation?
Ich vergleiche, aber die Python-Version ist anders. MySQL-Connector-Python war nicht mit Python 3.5 kompatibel.
[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