用pyodbc进行Python多处理和数据库访问“不安全”?

时间:2009-10-08 13:29:43

标签: python sql-server multiprocessing pickle pyodbc

问题:

我得到以下追溯,但不明白它的含义或解决方法:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "C:\Python26\lib\multiprocessing\forking.py", line 342, in main
    self = load(from_parent)
  File "C:\Python26\lib\pickle.py", line 1370, in load
    return Unpickler(file).load()
  File "C:\Python26\lib\pickle.py", line 858, in load
    dispatch[key](self)
  File "C:\Python26\lib\pickle.py", line 1083, in load_newobj
    obj = cls.__new__(cls, *args)
TypeError: object.__new__(pyodbc.Cursor) is not safe, use pyodbc.Cursor.__new__()

情况:

我有一个SQL Server数据库,里面装满了要处理的数据。我正在尝试使用多处理模块来并行化工作并利用计算机上的多个核心。我的一般班级结构如下:

  • MyManagerClass
    • 这是程序启动的主要类。
    • 创建两个multiprocessing.Queue对象,一个work_queue和一个write_queue
    • 它还会创建并启动其他进程,然后等待它们完成。
    • 注意:这是多处理的扩展.managers.BaseManager()
  • MyReaderClass
    • 此类从SQL Server数据库中读取数据。
    • 它会将项目放入work_queue
  • MyWorkerClass
    • 这是工作处理的地方。
    • 它从work_queue获取项目,并将完成的项目放入write_queue
  • MyWriterClass
    • 此类负责将已处理的数据写回SQL Server数据库。
    • 它从write_queue
    • 获取项目

这个想法是会有一位经理,一位读者,一位作家和许多工人。

其他详情:

我在stderr中得到了两次回溯,所以我认为它对读者来说只发生一次,对作者来说只发生一次。我的工作进程被创建得很好,但只是坐在那里直到我发送一个KeyboardInterrupt因为它们在work_queue中没有任何内容。

读者和编写者都有自己的数据库连接,在初始化时创建。

解决方案:

感谢Mark和Ferdinand Beyer提供的解决方案和问题。他们理所当然地指出Cursor对象不是“pickle-able”,这是多处理用于在进程之间传递信息的方法。

我的代码的问题是MyReaderClass(multiprocessing.Process)MyWriterClass(multiprocessing.Process)都在__init__()方法中连接到数据库。我在MyManagerClass中创建了这两个对象(即称为init方法),然后调用start()

因此它会创建连接和游标对象,然后尝试通过pickle将它们发送到子进程。我的解决方案是将连接和游标对象的实例化移动到run()方法,该方法在完全创建子进程之前不会被调用。

3 个答案:

答案 0 :(得分:10)

多处理依赖于pickle来在进程之间传递对象。 pyodbc连接和游标对象无法进行pickle。

>>> cPickle.dumps(aCursor)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python2.5/copy_reg.py", line 69, in _reduce_ex
    raise TypeError, "can't pickle %s objects" % base.__name__
TypeError: can't pickle Cursor objects
>>> cPickle.dumps(dbHandle)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python2.5/copy_reg.py", line 69, in _reduce_ex
    raise TypeError, "can't pickle %s objects" % base.__name__
TypeError: can't pickle Connection objects

“它将项目放入work_queue”,有哪些项目?是否有可能传递光标对象?

答案 1 :(得分:3)

错误是在pickle模块中引发的,所以你的DB-Cursor对象被某个地方腌制和取消连接(序列化为存储并再次反序列化为Python对象)。

我猜pyodbc.Cursor不支持酸洗。为什么要尝试保留游标对象呢?

检查您是否在工作链中的某个位置使用pickle,或者是否使用了隐含的。{/ p>

答案 2 :(得分:1)

pyodbc包含Python DB-API threadsafety level 1。这意味着线程不能共享连接,而且它根本不是线程安全的。

我不认为底层的线程安全的ODBC驱动程序会有所作为。如Pickling错误所述,它位于Python代码中。