Уведомления

Группа в Telegram: @pythonsu

#1 Май 29, 2011 18:09:40

plusplus
От:
Зарегистрирован: 2009-01-05
Сообщения: 418
Репутация: +  15  -
Профиль   Отправить e-mail  

Mysql многопоточность.

Решил, чтобы лишних проблем не было при работе с потоками всю работу с данными переложить на MySQL. В итоге, во много потоков шлю запросы SELECT и INSERT, буквально подряд, сервер выдает MySQL has gone away. Так и должно быть или я где-то накосячил? Подскажите, как решить проблему.



Офлайн

#2 Май 29, 2011 19:44:50

Lexander
От:
Зарегистрирован: 2008-09-19
Сообщения: 1139
Репутация: +  33  -
Профиль   Отправить e-mail  

Mysql многопоточность.

Проверьте, что все запросы шлются в одном и том же соединении.



Офлайн

#3 Май 30, 2011 07:21:39

plusplus
От:
Зарегистрирован: 2009-01-05
Сообщения: 418
Репутация: +  15  -
Профиль   Отправить e-mail  

Mysql многопоточность.

Lexander
Проверьте, что все запросы шлются в одном и том же соединении.
Да вроде так и делаю:
class Parser(threading.Thread):
def __init__(self,config):
threading.Thread.__init__(self)
self.config = config

def run(self):
while True:
try: item = queue.get_nowait()
except: break

try: self.posting(item)
except: traceback.print_exc()
time.sleep(0.5)

queue.task_done()
def append_to_base(self,links):
#with mutex:
for link in links:
#print link
link = link.replace("&","&")
if not "http"==link[:4]: continue
o = urlparse(link)
host = o.netloc
query = "SELECT * FROM main WHERE LOCATE('{0}',link);".format(esc_str(host))
self.db.query(query)
if not self.db.store_result().num_rows():
print link,"has been added."
query = "INSERT INTO main (link,status) VALUES('{0}','{1}')".format(esc_str(link),0)
self.db.query(query)
def posting(self,row):
t_id,link,status = row[0]
print link,"start."
url = link
post = Post()
the_page = post.get(url)

for regex in self.regulars:
if not the_page: continue
links = re.findall(regex,the_page)
self.append_to_base(links)
#with mutex:
query = "UPDATE main set status='1' where id='{0}';".format(t_id)
self.db.query(query)
def main():
config = ConfigParser.RawConfigParser()
config.read('settings.cfg')
threads = int(config.get("Basic","threads"))
regulars = [x.strip() for x in open(config.get("Basic","regulars"))]
args = dict(config.items('MySQL'))
db = _mysql.connect(host=args['host'], user=args['user'], passwd=args['passwd'], db=args['db'])
while True:
query_string = "SELECT * FROM main WHERE status='0' LIMIT 0,1000;"
db.query(query_string)
res = db.store_result()
if res.num_rows()<1:break
for i in xrange(res.num_rows()):
queue.put(res.fetch_row()) # заносим данные в очередь
#break
for i in xrange(threads):
t = Parser(config) # создаем нить
t.db = db
t.regulars = regulars
t.start() # стартуем
time.sleep(0.1)
queue.join()
print "Next round"
print "Done"
if __name__ == '__main__':
main()



Офлайн

#4 Май 30, 2011 08:41:23

plusplus
От:
Зарегистрирован: 2009-01-05
Сообщения: 418
Репутация: +  15  -
Профиль   Отправить e-mail  

Mysql многопоточность.

Видимо как раз наоборот надо, чтобы все запросы слались в разных соединениях. Перенес _mysql.connect в конструктор - заработало.



Офлайн

#5 Май 30, 2011 18:26:15

Lexander
От:
Зарегистрирован: 2008-09-19
Сообщения: 1139
Репутация: +  33  -
Профиль   Отправить e-mail  

Mysql многопоточность.

Так у вас все запросы к одной и той же таблице!
Похоже, Мускул просто затыкается от потока запросов в одном соединении.
Вы временно решили проблему, переложив ограничение с одного уровня на другой - повыше.
Точно также есть ограниение на макс. количество соединений и в один прекрасный момент некоторые соединения просто будут отвергаться сервером.

Кроме того, установка соединения - это все таки достаточно дорогая операция для сервера.

Я бы все копал в сторону настроек сервера БД (зависит от желаза) или все же изменил алгоритм.
Зачем здесь потоки, если все операции идут с одной таблицей?
Они ведь все равно упираются в производительность сервера БД.



Офлайн

#6 Июнь 3, 2011 20:51:01

plusplus
От:
Зарегистрирован: 2009-01-05
Сообщения: 418
Репутация: +  15  -
Профиль   Отправить e-mail  

Mysql многопоточность.

Потоки нужны для быстрого парсинга, не для работы с таблицей.

То есть оптимальным решением будет поставить блокировки при работе с таблицей? По-моему я так даже пробовал, но точно не помню. Сейчас проблема немножко другая - сервер ложится при 70к записях, как можно это предотвратить не подскажете?



Отредактировано (Июнь 3, 2011 20:52:00)

Офлайн

#7 Июнь 4, 2011 16:54:46

Lexander
От:
Зарегистрирован: 2008-09-19
Сообщения: 1139
Репутация: +  33  -
Профиль   Отправить e-mail  

Mysql многопоточность.

plusplus
Потоки нужны для быстрого парсинга, не для работы с таблицей.
Если результат парсинга сохраняется в одной и той же таблице, то я вам гарантирую - это и есть узкое место.
При вставке или обновлении записи мускул блокирует таблицу на запись. Т.е. одновременно у вас работает только 1 поток.
Иногда и на чтение - зависит от настроек.

plusplus
Сейчас проблема немножко другая - сервер ложится при 70к записях, как можно это предотвратить не подскажете?
Это от многих вещей зависит: начиная от мощности железа и заканчивая настройками Мускула.

Перво-наперво посмотрите статистику работы мускула. В некоторых инструментах для Мускула (PHPMyAdmin, например) есть средства для просмотра статистики. Он же дает рекомендации, что нужно сделать, если то или иное значение статистики плохое.



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version