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 个回答
一般来说,这个错误可能是随机出现的。我遇到过这个错误,但在再次运行程序时却没有出现这个错误。我运行了我的程序(虽然和mysql_db没关系,但也很复杂)5次。只在第一次和第四次运行时发现了这个错误。
我也遇到过同样的问题,不过我想了一下,尽量避免多个线程同时访问数据库。经过进一步思考,我觉得让很多线程同时连接数据库其实是不太好的做法(或者说这事儿挺复杂的)。可以考虑一些批量读取和写入的方法,把多线程的处理放在数据库之外。
这可能还是Python绑定里的一个bug,但我通过简化程序访问数据库的方式,以及在真正需要并行处理的地方进行多线程,取得了一些进展。希望这对你有帮助!
我在使用MySQLdb时,在OSX上遇到了同样的malloc错误。导致我出错的原因是我在多个线程之间共享MySQLdb连接。每个线程使用一个连接解决了我的问题。
根据文档 http://mysql-python.sourceforge.net/MySQLdb.html:
MySQL协议无法处理多个线程同时使用同一个连接。早期版本的MySQLdb通过锁定来实现线程安全,但这只支持两个线程。虽然使用标准的Cursor类(它使用mysql_store_result())来实现这一点并不太难,但使用SSCursor就复杂多了(它使用mysql_use_result();使用后者时,必须确保在执行另一个查询之前,所有行都已读取完)。此外,事务的引入使事情变得更加复杂,因为事务在游标执行查询时开始,但在Connection对象执行COMMIT或ROLLBACK时结束。在事务进行时,两个线程是无法共享连接的,查询执行时也是如此。这使得代码变得过于复杂,根本不值得。
总的来说,就是:不要在多个线程之间共享连接。这真的不值得你我花费精力,最终可能还会影响性能,因为MySQL服务器为每个连接运行一个单独的线程。你当然可以做一些事情,比如在连接池中缓存连接,然后一次只给一个线程使用。如果让两个线程同时使用一个连接,MySQL客户端库可能会崩溃。你已经被警告了。