13

问题:

我收到以下回溯,但不明白它的含义或如何解决它:

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 数据库。我正在尝试使用多处理模块来并行化工作并利用我计算机上的多个内核。我的一般班级结构如下:

  • 我的管理器类
    • 这是程序开始的主类。
    • 它创建了两个 multiprocessing.Queue 对象,一个work_queue和一个write_queue
    • 它还创建并启动其他进程,然后等待它们完成。
    • 注意:这不是multiprocessing.managers.BaseManager() 的扩展
  • 我的读者类
    • 此类从 SQL Server 数据库中读取数据。
    • 它将项目放在work_queue.
  • 我的工人阶级
    • 这是工作处理发生的地方。
    • 它从 中获取项目work_queue并将完成的项目放入write_queue.
  • 我的作家类
    • 该类负责将处理后的数据写回 SQL Server 数据库。
    • 它从write_queue.

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

其他详情:

我在stderr中得到了两次回溯,所以我认为它发生在读者和作者一次。我的工作进程创建得很好,但只是坐在那里,直到我发送一个 KeyboardInterrupt,因为它们在work_queue.

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

解决方案:

感谢 Mark 和 Ferdinand Beyer 的回答和问题导致了这个解决方案。他们正确地指出 Cursor 对象不是“pickle-able”,这是多处理用于在进程之间传递信息的方法。

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

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

4

3 回答 3

13

多处理依赖于酸洗来在进程之间通信对象。pyodbc 连接和游标对象不能被腌制。

>>> 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”,哪些项目?光标对象是否也有可能被传递?

于 2009-10-08T14:02:46.340 回答
3

该错误在pickle模块内引发,因此您的 DB-Cursor 对象在某处被腌制和解封(序列化到存储并再次反序列化到 Python 对象)。

我想这pyodbc.Cursor不支持酸洗。你为什么要尝试持久化光标对象呢?

检查您是否使用pickle了工作链中的某个位置,或者它是否被隐式使用。

于 2009-10-08T13:36:22.820 回答
3

pyodbc具有 Python DB-API线程安全级别 1。这意味着线程不能共享连接,而且它根本不是线程安全的。

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

于 2014-10-30T02:50:08.710 回答