Запрос Peewee работает медленно с многопоточностью
Я нашел этот интересный сценарий при использовании peewee с потоковой передачей.
У меня таблица выглядит так
class Locks(BaseModel):
_id = AutoField()
name = CharField(unique=True, index=True)
last_modify_time = DateTimeField(constraints=[SQL("DEFAULT CURRENT_TIMESTAMP")])
owner = CharField()
class Meta:
table_name = 'locks'
И я хочу запросить количество записей, которые он содержит, с помощью этого sql:
sql = Locks.select().where(Locks.name == 'test')
sql.execute()
Достаточно просто, правда? Но я обнаружил, что он работает ужасно медленно. Без потоковой передачи время, необходимое для запроса базы данных внутри нашей сети, составляет 3 - 5 мс. Но когда появилась многопоточность, она выросла до 70 мс.
Код выглядит так:
def test_lock():
sql = Locks.select().where(Locks.name == 'test')
sql.execute()
def run_thread():
test = threading.Thread(target=test_lock)
test.start()
test.join()
yappi.set_clock_type('Wall')
yappi.start()
for _ in range(100):
run_thread()
yappi.stop()
Результаты yappi выглядят так
7 ncalls tottime percall cumtime percall filename:lineno(function)
8 100 0.002 0.000 8.191 0.082 /home/data/EBS_Operation/services/task_center.py:337(run_thread)
9 200 0.004 0.000 8.167 0.041 /usr/lib64/python2.7/threading.py:308(_Condition.wait)
10 100 0.003 0.000 7.484 0.075 /usr/lib64/python2.7/threading.py:754(Thread.run)
11 100 0.005 0.000 7.477 0.075 /home/data/EBS_Operation/services/task_center.py:330(test_lock)
12 100 0.001 0.000 7.433 0.074 /usr/lib/python2.7/site-packages/peewee.py:1880(ModelSelect.inner)
13 100 0.001 0.000 7.432 0.074 /usr/lib/python2.7/site-packages/peewee.py:1955(ModelSelect.execute)
14 100 0.005 0.000 7.431 0.074 /usr/lib/python2.7/site-packages/peewee.py:2127(ModelSelect._execute)
15 100 0.003 0.000 7.418 0.074 /usr/lib/python2.7/site-packages/peewee.py:3109(MySQLDatabase.execute)
16 100 0.002 0.000 7.361 0.074 /usr/lib64/python2.7/threading.py:913(Thread.join)
17 100 0.009 0.000 7.009 0.070 /usr/lib/python2.7/site-packages/peewee.py:3086(MySQLDatabase.execute_sql)
18 100 0.008 0.000 6.653 0.067 /usr/lib/python2.7/site-packages/peewee.py:3078(MySQLDatabase.cursor)
19 100 0.005 0.000 6.638 0.066 /usr/lib/python2.7/site-packages/peewee.py:3023(MySQLDatabase.connect)
20 100 0.002 0.000 6.632 0.066 /usr/lib/python2.7/site-packages/peewee.py:3930(MySQLDatabase._connect)
21 100 0.012 0.000 6.630 0.066 /usr/lib64/python2.7/site-packages/MySQLdb/__init__.py:78(Connect)
22 100 6.415 0.064 6.618 0.066 /usr/lib64/python2.7/site-packages/MySQLdb/connections.py:62(Connection.__init__
)
23 100 0.002 0.000 0.817 0.008 /usr/lib64/python2.7/threading.py:728(Thread.start)
24 100 0.001 0.000 0.810 0.008 /usr/lib64/python2.7/threading.py:604(_Event.wait)
25 100/3400 0.031 0.000 0.392 0.000 /usr/lib/python2.7/site-packages/peewee.py:604(Context.sql)
26 100 0.028 0.000 0.388 0.004 /usr/lib/python2.7/site-packages/peewee.py:2350(ModelSelect.__sql__)
27 200 0.010 0.000 0.193 0.001 /usr/lib/python2.7/site-packages/peewee.py:1744(NodeList.__sql__)
28 100 0.003 0.000 0.182 0.002 /usr/lib64/python2.7/logging/__init__.py:1127(Logger.debug)
29 500 0.005 0.000 0.181 0.000 /usr/lib/python2.7/site-packages/peewee.py:4504(AutoField.__sql__)
30 100 0.006 0.000 0.172 0.002 /usr/lib64/python2.7/logging/__init__.py:1249(Logger._log)
31 100 0.001 0.000 0.164 0.002 /usr/lib/python2.7/site-packages/peewee.py:7141(ModelSelect.__sql_selection__)
32 500 0.014 0.000 0.158 0.000 /usr/lib/python2.7/site-packages/peewee.py:1234(Column.__sql__)
Есть идеи, как это было?
1 ответ
Peewee хранит состояние подключения в локальных потоках. Таким образом, каждый поток имеет отдельное соединение. Если вы посмотрите на результаты своего профилирования, я думаю, что поучительная строка:
22 100 6.415 0.064 6.618 0.066 /usr/lib64/python2.7/site-packages/MySQLdb/connections.py:62(Connection.__init__
Вы устанавливаете 100 различных подключений, а это дорого.
Предположительно, как только вы их настроите, запросы будут несколько более производительными.