python: Mac OS X. ошибка malloc. освобожденный указатель не был выделен. прерывание ловушки 6

Я использую многопоточный скрипт на Python. он будет сканировать сеть и вставлять / обновлять в mysql. вот мой код

mythread.py

import threading
import time

class MyThread (threading.Thread):
    def __init__(self, threadID, threadname, q):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.threadname = threadname
        self.queue = q
        self.__exitFlag = False
        self.__signal_lock = threading.Lock()

    def run(self):
        print "Starting " + self.threadname
        self.process_data()
        print "Exiting " + self.threadname

    def stop(self):
        with self.__signal_lock:
            self.__exitFlag = True

    def process_data(self):
        while not self.__exitFlag:
            if not self.queue.empty():
                data = self.queue.get()
                # crawl data from the web...
                # update to mysql
                # assuming we have already connected mysql:
                # db = MySQLDb()
                # db.connect
                query = ""
                db.query(query)

mysql_db.py

class MySQLDb:
    conn = None

    def connect(self):
        self.conn = MySQLdb.connect(
            host="127.0.0.1",
            user = "root",
            passwd = "password",
            db = "moviestats")

        self.cursor = self.conn.cursor(MySQLdb.cursors.DictCursor)

    def query(self, sql):
        try:
            self.cursor.execute(sql)
            self.conn.commit()
        except (AttributeError, MySQLdb.OperationalError):
            # solution to: MySQL server has gone away
            self.cursor.close()
            self.connect()
            self.cursor = self.conn.cursor(MySQLdb.cursors.DictCursor)
            self.cursor.execute(sql)
            self.conn.commit()

Вот журнал ошибок:

Process:         Python [905]
Path:            /Library/Frameworks/Python.framework/Versions/2.7/Resources/Python.app/Contents/MacOS/Python
Identifier:      Python
Version:         2.7.7 (2.7.7)
Code Type:       X86-64 (Native)
Parent Process:  bash [751]
Responsible:     Terminal [410]
User ID:         501

Date/Time:       2014-07-09 22:31:43.221 +0800
OS Version:      Mac OS X 10.9.3 (13D65)
Report Version:  11
....

....
Crashed Thread:  5

Exception Type:  EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000

Application Specific Information:
abort() called
*** error for object 0x100a4b600: pointer being freed was not allocated
......
Thread 5 Crashed:
0   libsystem_kernel.dylib          0x00007fff83153866 __pthread_kill + 10
1   libsystem_pthread.dylib         0x00007fff8de8735c pthread_kill + 92
2   libsystem_c.dylib               0x00007fff8ef88b1a abort + 125
3   libsystem_malloc.dylib          0x00007fff8220707f free + 411
4   libmysqlclient.18.dylib         0x0000000101027302 vio_delete + 44
5   libmysqlclient.18.dylib         0x000000010100709a end_server + 48
6   libmysqlclient.18.dylib         0x0000000101006f81 cli_safe_read + 49
7   libmysqlclient.18.dylib         0x000000010100b469 cli_read_query_result + 26
8   libmysqlclient.18.dylib         0x000000010100a648 mysql_real_query + 83
9   _mysql.so                       0x0000000100533be8 _mysql_ConnectionObject_query + 85
10  org.python.python               0x00000001000c2fad PyEval_EvalFrameEx + 21405
11  org.python.python               0x00000001000c3bfa PyEval_EvalFrameEx + 24554
12  org.python.python               0x00000001000c3bfa PyEval_EvalFrameEx + 24554
13  org.python.python               0x00000001000c4fb3 PyEval_EvalCodeEx + 2115
14  org.python.python               0x00000001000c33f0 PyEval_EvalFrameEx + 22496
15  org.python.python               0x00000001000c3bfa PyEval_EvalFrameEx + 24554
16  org.python.python               0x00000001000c3bfa PyEval_EvalFrameEx + 24554
17  org.python.python               0x00000001000c4fb3 PyEval_EvalCodeEx + 2115
18  org.python.python               0x00000001000c33f0 PyEval_EvalFrameEx + 22496
19  org.python.python               0x00000001000c3bfa PyEval_EvalFrameEx + 24554
20  org.python.python               0x00000001000c3bfa PyEval_EvalFrameEx + 24554
21  org.python.python               0x00000001000c3bfa PyEval_EvalFrameEx + 24554
22  org.python.python               0x00000001000c4fb3 PyEval_EvalCodeEx + 2115
23  org.python.python               0x000000010003eac0 function_call + 176
24  org.python.python               0x000000010000ceb2 PyObject_Call + 98
25  org.python.python               0x000000010001f56d instancemethod_call + 365
26  org.python.python               0x000000010000ceb2 PyObject_Call + 98
27  org.python.python               0x00000001000bc957 PyEval_CallObjectWithKeywords + 87
28  org.python.python               0x0000000100102f27 t_bootstrap + 71
29  libsystem_pthread.dylib         0x00007fff8de86899 _pthread_body + 138
30  libsystem_pthread.dylib         0x00007fff8de8672a _pthread_start + 137
31  libsystem_pthread.dylib         0x00007fff8de8afc9 thread_start + 13

Я запустил скрипт с 50 потоками. Ошибка происходит с перебоями, но она повторяется. Я сузил проблему, и это из-за вставки / обновления MySQL. Я читал, что это может быть связано с проблемой параллелизма, но как мне это исправить?

3 ответа

Я столкнулся с той же ошибкой malloc на OSX, используя MySQLdb. Моей ошибкой было то, что я разделял соединения MySQLdb между потоками. Использование соединения в потоке исправило это для меня.

Из документации http://mysql-python.sourceforge.net/MySQLdb.html:

Протокол MySQL не может обрабатывать несколько потоков, используя одно и то же соединение одновременно. В некоторых более ранних версиях MySQLdb блокировка использовалась для обеспечения безопасности потока 2. Хотя это не очень сложно реализовать с помощью стандартного класса Cursor (который использует mysql_store_result()), он усложняется SSCursor (который использует mysql_use_result(); с последним Вы должны убедиться, что все строки были прочитаны, прежде чем можно будет выполнить другой запрос. Это дополнительно усложняется добавлением транзакций, поскольку транзакции начинаются, когда курсор выполняет запрос, но заканчиваются, когда COMMIT или ROLLBACK выполняются объектом Connection. потоки просто не могут совместно использовать соединение во время выполнения транзакции, в дополнение к невозможности поделиться им во время выполнения запроса, что чрезмерно усложняет код до такой степени, что оно просто не стоит.

Общий итог этого: не делиться соединениями между потоками. Это действительно не стоит ваших или моих усилий, и в конечном итоге, вероятно, ухудшит производительность, поскольку сервер MySQL запускает отдельный поток для каждого соединения. Вы, конечно, можете делать такие вещи, как соединения с кешем в пуле, и передавать эти соединения одному потоку за раз. Если вы позволите двум потокам использовать соединение одновременно, клиентская библиотека MySQL, вероятно, выскочит и умрет. Вы были предупреждены.

У меня была та же проблема, но я думал о способах не многопоточного доступа к базе данных. И после дальнейших размышлений я считаю плохой практикой иметь множество потоков со связями (или, по крайней мере, это может быть сложным делом). Подумайте о том, как выполнять массовое чтение и запись, а также выполнять многопоточность обработки без участия базы данных.

Это может все еще быть ошибкой в ​​привязке Python, но я смог добиться прогресса, упростив способ, которым программа обращалась к базе данных, и распараллеливая код, где это действительно нужно было распараллелить. Надеюсь это поможет!

В целом эта ошибка может быть стохастической. Я столкнулся с этой ошибкой, но после запуска программы снова не получил ошибку. Я запускал свою программу (которая не связана с mysql_db, хотя и сложна) 5 раз. Я нашел эту ошибку только на первом и четвертом прогоне.

Другие вопросы по тегам