Форум сайта python.su
Здравствуйте, нужна помощь вот в такой ситуации. Есть многопоточный бот, который собирает информацию с досок объявлений и сохраняет некоторые даные в БД. Функции: Получить все записи, Добавить запись, Обновить запись, Удалить запись. Запущен он на Ubuntu 16 на локалхосте. Происходит следующее, бот работает какое то время, и создает скажем каждые 10 минут по новому потоку, записывает данные в базу данных.
d_id=InsertMain(message.chat.id,text) bot.send_message(message.chat.id,config.SuccesAppend) c_id=message.chat.id thread_ = threading.Thread(target=Select,args=[c_id,d_id]) thread_.setDaemon(True) thread_.setName=str(c_id) thread_.start()
def Select(mId,d_id): while True: Wait=randint(0,1) WaitInput = randint(20,30) time.sleep(1) lock.acquire() try: result=conn.SelectMainAndID(d_id) finally: lock.release() if result: for value in result: . else: #bot.send_message(mId,config.NoLink) logging.error('BD Error'+str(id_)) continue
class Base: def SelectMain(self,mId): try: self.db = MySQLdb.connect(host="localhost", user="test", passwd="password", db="testdb", charset='utf8') self.cursor = self.db.cursor() sql ="SELECT * FROM main WHERE M_ID ='%s' FOR UPDATE "% (mId) self.cursor.execute(sql) data = self.cursor.fetchall() return data except Exception: print ''.join(traceback.format_exception(*sys.exc_info())) return False def SelectMainAndID(self,mId): try: self.db = MySQLdb.connect(host="localhost", user="test", passwd="password", db="testdb", charset='utf8') self.cursor = self.db.cursor() sql ="SELECT * FROM main WHERE id ='%s' FOR UPDATE"% (mId) self.cursor.execute(sql) data = self.cursor.fetchall() self.db.close() return data except: return False def DeleteMain(self,ID): try: self.db = MySQLdb.connect(host="localhost", user="test", passwd="password", db="testdb", charset='utf8') self.cursor = self.db.cursor() sql = "DELETE FROM `main` WHERE id = '%s'" % (ID) self.cursor.execute(sql) self.db.commit() self.db.close() return True except: return False def UpdateMain(self,flag,url,mId): try: self.db = MySQLdb.connect(host="localhost", user="test", passwd="password", db="testdb", charset='utf8') self.cursor = self.db.cursor() self.cursor.execute("""UPDATE main SET CheckUrl=%s,StartUrl=%s WHERE id=%s""",(flag,url,mId)) self.db.commit() self.db.close() return True except: return False
Офлайн
Какие вы себе матерые грабли соорудили.
Запросы в базу могут блокировать друг друга. Скорее всего на такую блокировку вы и нарываетесь.
Дальше, установка соединения для каждого запроса это очень дорого, обычно делают пул. Я бы сделал один поток работающий с базой данных - читает из базы и кладет в очередь, потоки берут данные из очереди, обрабатывают и кладут в другую, поток читает из нее и сбрасывает в базу. Соединение постоянное, нет взаимоблокировок, ну и плюсом можно читать/писать пачками строк.
Ну и вишенкой на торте, используйте биндинг параметров в запросах везде. Не надо интерполяции строк, типа
sql = "DELETE FROM `main` WHERE id = '%s'" % (ID)
Отредактировано PooH (Март 3, 2017 04:37:01)
Офлайн
PooHДа я первоначально делал очередь и все было нормально, но потом когда требования к боту усложнилось, пришлось отказаться, не буду вдаваться в подробности. Про биндинг спасибо, да действительно привычка, буду отучаться. Можно подробнее про пулл, тк вариант одного соединения не устраивает, а кроме как создать новое соединение ничего не пришло в голову, я даже на каждый созданый поток пытался создать соединение, но потом понял, что там вообще лес проблем. Сейчас при одном соединении на весь процесс следующие получаю при одновременных запросах:
Какие вы себе матерые грабли соорудили.
Офлайн
db.store_result() - проблемма решилась этим
Офлайн
pandarado@gmail.comДа просто список соединений, каждый поток запрашивает соединение у него, а после работы не закрывает, а отдает обратно. Естественно доступ к пулу из потоков надо синхронизировать. Вообщем то там нюансов много, так что лучше поискать готовую библиотеку.
Можно подробнее про пулл,
Офлайн