Las actualizaciones de variables globales de multiprocesamiento no se devuelven al padre.
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 dataDV03
y 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]:
Cuando usas multiprocessing
para 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 multiprocessing
proporciona utilizan pickle para transferir datos. Todos los datos transferidos mediante poderes deben poder ser conservados ; que incluye todos los objetos que Manager
proporciona un . Citas relevantes (énfasis mío):
Asegúrese de que los argumentos de los métodos de los proxy sean seleccionables.
Y (en la Manager
sección):
Otros procesos pueden acceder a los objetos compartidos mediante servidores proxy .
Queue
Tambié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 ctype
objeto; 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 LORR
una 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 LORR
instancia 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 Queue
s 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
@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