Las actualizaciones de variables globales de multiprocesamiento no se devuelven al padre.

Resuelto Buoy asked hace 12 años • 0 respuestas

Estoy intentando devolver valores de subprocesos, pero lamentablemente estos valores no se pueden seleccionar. Así que utilicé variables globales en el módulo de subprocesos con éxito, pero no pude recuperar las actualizaciones realizadas en los subprocesos cuando utilicé el módulo de multiprocesamiento. Espero que me esté perdiendo algo.

Los resultados impresos al final son siempre los mismos que los valores iniciales dados los vars dataDV03y dataDV04. Los subprocesos están actualizando estas variables globales pero estas variables globales permanecen sin cambios en el padre.

import multiprocessing

# NOT ABLE to get python to return values in passed variables.

ants = ['DV03', 'DV04']
dataDV03 = ['', '']
dataDV04 = {'driver': '', 'status': ''}


def getDV03CclDrivers(lib):  # call global variable
    global dataDV03
    dataDV03[1] = 1
    dataDV03[0] = 0

# eval( 'CCL.' + lib + '.' +  lib + '( "DV03" )' ) these are unpicklable instantiations

def getDV04CclDrivers(lib, dataDV04):   # pass global variable
    dataDV04['driver'] = 0  # eval( 'CCL.' + lib + '.' +  lib + '( "DV04" )' )


if __name__ == "__main__":

    jobs = []
    if 'DV03' in ants:
        j = multiprocessing.Process(target=getDV03CclDrivers, args=('LORR',))
        jobs.append(j)

    if 'DV04' in ants:
        j = multiprocessing.Process(target=getDV04CclDrivers, args=('LORR', dataDV04))
        jobs.append(j)

    for j in jobs:
        j.start()

    for j in jobs:
        j.join()

    print 'Results:\n'
    print 'DV03', dataDV03
    print 'DV04', dataDV04

No puedo publicar mi pregunta, así que intentaré editar el original.

Aquí está el objeto que no se puede decapar:

In [1]: from CCL import LORR
In [2]: lorr=LORR.LORR('DV20', None)
In [3]: lorr
Out[3]: <CCL.LORR.LORR instance at 0x94b188c>

Este es el error que se devuelve cuando uso un grupo de multiprocesamiento para devolver la instancia al padre:

Thread getCcl (('DV20', 'LORR'),)
Process PoolWorker-1:
Traceback (most recent call last):
File "/alma/ACS-10.1/casa/lib/python2.6/multiprocessing/process.py", line 232, in _bootstrap
self.run()
File "/alma/ACS-10.1/casa/lib/python2.6/multiprocessing/process.py", line 88, in run
self._target(*self._args, **self._kwargs)
File "/alma/ACS-10.1/casa/lib/python2.6/multiprocessing/pool.py", line 71, in worker
put((job, i, result))
File "/alma/ACS-10.1/casa/lib/python2.6/multiprocessing/queues.py", line 366, in put
return send(obj)
UnpickleableError: Cannot pickle <type 'thread.lock'> objects
In [5]: dir(lorr)
Out[5]:
['GET_AMBIENT_TEMPERATURE',
 'GET_CAN_ERROR',
 'GET_CAN_ERROR_COUNT',
 'GET_CHANNEL_NUMBER',
 'GET_COUNT_PER_C_OP',
 'GET_COUNT_REMAINING_OP',
 'GET_DCM_LOCKED',
 'GET_EFC_125_MHZ',
 'GET_EFC_COMB_LINE_PLL',
 'GET_ERROR_CODE_LAST_CAN_ERROR',
 'GET_INTERNAL_SLAVE_ERROR_CODE',
 'GET_MAGNITUDE_CELSIUS_OP',
 'GET_MAJOR_REV_LEVEL',
 'GET_MINOR_REV_LEVEL',
 'GET_MODULE_CODES_CDAY',
 'GET_MODULE_CODES_CMONTH',
 'GET_MODULE_CODES_DIG1',
 'GET_MODULE_CODES_DIG2',
 'GET_MODULE_CODES_DIG4',
 'GET_MODULE_CODES_DIG6',
 'GET_MODULE_CODES_SERIAL',
 'GET_MODULE_CODES_VERSION_MAJOR',
 'GET_MODULE_CODES_VERSION_MINOR',
 'GET_MODULE_CODES_YEAR',
 'GET_NODE_ADDRESS',
 'GET_OPTICAL_POWER_OFF',
 'GET_OUTPUT_125MHZ_LOCKED',
 'GET_OUTPUT_2GHZ_LOCKED',
 'GET_PATCH_LEVEL',
 'GET_POWER_SUPPLY_12V_NOT_OK',
 'GET_POWER_SUPPLY_15V_NOT_OK',
 'GET_PROTOCOL_MAJOR_REV_LEVEL',
 'GET_PROTOCOL_MINOR_REV_LEVEL',
 'GET_PROTOCOL_PATCH_LEVEL',
 'GET_PROTOCOL_REV_LEVEL',
 'GET_PWR_125_MHZ',
 'GET_PWR_25_MHZ',
 'GET_PWR_2_GHZ',
 'GET_READ_MODULE_CODES',
 'GET_RX_OPT_PWR',
 'GET_SERIAL_NUMBER',
 'GET_SIGN_OP',
 'GET_STATUS',
 'GET_SW_REV_LEVEL',
 'GET_TE_LENGTH',
 'GET_TE_LONG_FLAG_SET',
 'GET_TE_OFFSET_COUNTER',
 'GET_TE_SHORT_FLAG_SET',
 'GET_TRANS_NUM',
 'GET_VDC_12',
 'GET_VDC_15',
 'GET_VDC_7',
 'GET_VDC_MINUS_7',
 'SET_CLEAR_FLAGS',
 'SET_FPGA_LOGIC_RESET',
 'SET_RESET_AMBSI',
 'SET_RESET_DEVICE',
 'SET_RESYNC_TE',
 'STATUS',
 '_HardwareDevice__componentName',
 '_HardwareDevice__hw',
 '_HardwareDevice__stickyFlag',
 '_LORRBase__logger',
 '__del__',
 '__doc__',
 '__init__',
 '__module__',
 '_devices',
 'clearDeviceCommunicationErrorAlarm',
 'getControlList',
 'getDeviceCommunicationErrorCounter',
 'getErrorMessage',
 'getHwState',
 'getInternalSlaveCanErrorMsg',
 'getLastCanErrorMsg',
 'getMonitorList',
 'hwConfigure',
 'hwDiagnostic',
 'hwInitialize',
 'hwOperational',
 'hwSimulation',
 'hwStart',
 'hwStop',
 'inErrorState',
 'isMonitoring',
 'isSimulated']

In [6]:
Buoy avatar Jun 16 '12 00:06 Buoy
Aceptado

Cuando usas multiprocessingpara abrir un segundo proceso, se crea una instancia completamente nueva de Python, con su propio estado global. Ese estado global no se comparte, por lo que los cambios realizados por los procesos secundarios en las variables globales serán invisibles para el proceso principal.

Además, la mayoría de las abstracciones que multiprocessingproporciona utilizan pickle para transferir datos. Todos los datos transferidos mediante poderes deben poder ser conservados ; que incluye todos los objetos que Managerproporciona un . Citas relevantes (énfasis mío):

Asegúrese de que los argumentos de los métodos de los proxy sean seleccionables.

Y (en la Managersección):

Otros procesos pueden acceder a los objetos compartidos mediante servidores proxy .

QueueTambién requieren datos seleccionables; Los documentos no lo dicen, pero una prueba rápida lo confirma:

import multiprocessing
import pickle

class Thing(object):
    def __getstate__(self):
        print 'got pickled'
        return self.__dict__
    def __setstate__(self, state):
        print 'got unpickled'
        self.__dict__.update(state)

q = multiprocessing.Queue()
p = multiprocessing.Process(target=q.put, args=(Thing(),))
p.start()
print q.get()
p.join()

Producción:

$ python mp.py 
got pickled
got unpickled
<__main__.Thing object at 0x10056b350>

El único enfoque que podría funcionar para usted, si realmente no puede seleccionar los datos, es encontrar una manera de almacenarlos como un ctypeobjeto; Luego se puede pasar una referencia a la memoria a un proceso hijo . Esto me parece bastante dudoso; Yo nunca lo he hecho. Pero podría ser una posible solución para usted.

Dada su actualización, parece que necesita saber mucho más sobre las partes internas de un archivo LORR. ¿ Es LORRuna clase? ¿Puedes subclasificarlo? ¿Es una subclase de otra cosa? ¿Cuál es su MRO? (Intente LORR.__mro__publicar el resultado si funciona). Si es un objeto de Python puro, podría ser posible subclasificarlo, creando a __setstate__y a __getstate__para habilitar el decapado.

Otro enfoque podría ser descubrir cómo obtener los datos relevantes de una LORRinstancia y pasarlos a través de una cadena simple. Ya que dices que realmente sólo quieres llamar a los métodos del objeto, ¿por qué no hacerlo usando Queues para enviar mensajes de un lado a otro? En otras palabras, algo como esto (esquemáticamente):

Main Process              Child 1                       Child 2
                          LORR 1                        LORR 2 
child1_in_queue     ->    get message 'foo'
                          call 'foo' method
child1_out_queue    <-    return foo data string
child2_in_queue                   ->                    get message 'bar'
                                                        call 'bar' method
child2_out_queue                  <-                    return bar data string
senderle avatar Jun 15 '2012 18:06 senderle

@DBlas te brinda una URL rápida y una referencia a la clase Manager en una respuesta, pero creo que todavía es un poco vago, así que pensé que podría ser útil para ti verlo aplicado...

import multiprocessing
from multiprocessing import Manager

ants = ['DV03', 'DV04']

def getDV03CclDrivers(lib, data_dict):  
    data_dict[1] = 1
    data_dict[0] = 0

def getDV04CclDrivers(lib, data_list):   
    data_list['driver'] = 0  


if __name__ == "__main__":

    manager = Manager()
    dataDV03 = manager.list(['', ''])
    dataDV04 = manager.dict({'driver': '', 'status': ''})

    jobs = []
    if 'DV03' in ants:
        j = multiprocessing.Process(
                target=getDV03CclDrivers, 
                args=('LORR', dataDV03))
        jobs.append(j)

    if 'DV04' in ants:
        j = multiprocessing.Process(
                target=getDV04CclDrivers, 
                args=('LORR', dataDV04))
        jobs.append(j)

    for j in jobs:
        j.start()

    for j in jobs:
        j.join()

    print 'Results:\n'
    print 'DV03', dataDV03
    print 'DV04', dataDV04

Debido a que el multiprocesamiento en realidad utiliza procesos separados, no se pueden simplemente compartir variables globales porque estarán en "espacios" completamente diferentes en la memoria. Lo que le hagas a un global bajo un proceso no se reflejará en otro. Aunque admito que parece confuso desde la forma en que lo ves, todo está ahí en el mismo código, entonces "¿por qué esos métodos no deberían tener acceso a lo global"? Es más difícil hacerse a la idea de que se ejecutarán en procesos diferentes.

La clase Manager se proporciona para actuar como un proxy para estructuras de datos que pueden transportar información de un lado a otro entre procesos. Lo que hará es crear un dictado y una lista especiales desde un administrador, pasarlos a sus métodos y operarlos localmente.

Datos no seleccionables

Para su objeto LORR especializado, es posible que necesite crear algo como un proxy que pueda representar el estado seleccionable de la instancia.

No es muy robusto ni se ha probado mucho, pero te da una idea.

class LORRProxy(object):

    def __init__(self, lorrObject=None):
        self.instance = lorrObject

    def __getstate__(self):
        # how to get the state data out of a lorr instance
        inst = self.instance
        state = dict(
            foo = inst.a,
            bar = inst.b,
        )
        return state

    def __setstate__(self, state):
        # rebuilt a lorr instance from state
        lorr = LORR.LORR()
        lorr.a = state['foo']
        lorr.b = state['bar']
        self.instance = lorr
jdi avatar Jun 15 '2012 18:06 jdi