Hang in Python script using SQLAlchemy and multiprocessing

后端 未结 4 1873
北海茫月
北海茫月 2021-01-05 06:48

Consider the following Python script, which uses SQLAlchemy and the Python multiprocessing module. This is with Python 2.6.6-8+b1(default) and SQLAlchemy 0.6.3-3 (default)

4条回答
  •  猫巷女王i
    2021-01-05 07:27

    I don't know about the cause of the original exception. However, multiprocessing's problems with "bad" exceptions is really down to how pickling works. I think the sqlachemy exception class is broken.

    If an exception class has an __init__() method which does not call BaseException.__init__() (directly or indirectly) then self.args probably will not be set properly. BaseException.__reduce__() (which is used by the pickle protocol) assumes that a copy of an exception e can be recreated by just doing

    type(e)(*e.args)
    

    For example

    >>> e = ValueError("bad value")
    >>> e
    ValueError('bad value',)
    >>> type(e)(*e.args)
    ValueError('bad value',)
    

    If this invariant does not hold then pickling/unpickling will fail. So instances of

    class BadExc(Exception):
        def __init__(self, a):
            '''Non-optional param in the constructor.'''
            self.a = a
    

    can be pickled, but the result cannot be unpickled:

    >>> from cPickle import loads, dumps
    >>> class BadExc(Exception):
    ...     def __init__(self, a):
    ...         '''Non-optional param in the constructor.'''
    ...         self.a = a
    ...
    >>> loads(dumps(BadExc(1)))
    Traceback (most recent call last):
      File "", line 1, in 
    TypeError: ('__init__() takes exactly 2 arguments (1 given)', , ())
    

    But instances of

    class GoodExc1(Exception):
        def __init__(self, a):
            '''Non-optional param in the constructor.'''
            Exception.__init__(self, a)
            self.a = a
    

    or

    class GoodExc2(Exception):
        def __init__(self, a):
            '''Non-optional param in the constructor.'''
            self.args = (a,)
            self.a = a
    

    can be successfully pickled/unpickled.

    So you should ask the developers of sqlalchemy to fix their exception classes. In the mean time you can probably use copy_reg.pickle() to override BaseException.__reduce__() for the troublesome classes.

提交回复
热议问题