问题描述
我正在尝试从子流程中返回值,但是不幸的是这些值是无法拾取的.因此,我在线程模块中成功使用了全局变量,但在使用多处理模块时却无法检索在子流程中完成的更新.我希望我想念一些东西.
I am trying to return values from subprocesses but these values are unfortunately unpicklable. So I used global variables in threads module with success but have not been able to retrieve updates done in subprocesses when using multiprocessing module. I hope I'm missing something.
在给定变量dataDV03
和dataDV04
的情况下,最后打印的结果始终与初始值相同.子进程正在更新这些全局变量,但这些全局变量在父级中保持不变.
The results printed at the end are always the same as initial values given the vars dataDV03
and dataDV04
. The subprocesses are updating these global variables but these global variables remain unchanged in the parent.
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
我无法发布问题,因此将尝试编辑原始内容.
I cannot post to my question so will try to edit the original.
这里是不可腌制的对象
In [1]: from CCL import LORR
In [2]: lorr=LORR.LORR('DV20', None)
In [3]: lorr
Out[3]: <CCL.LORR.LORR instance at 0x94b188c>
这是我使用多重处理时返回的错误.池将实例返回给父级:
This is the error returned when I use a multiprocessing.Pool to return the instance back to the parent:
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]:
推荐答案
使用multiprocessing
打开第二个进程时,具有自身全局状态的Python的全新实例是创建.该全局状态不会共享,因此子进程对全局变量所做的更改对于父进程将是不可见的.
When you use multiprocessing
to open a second process, an entirely new instance of Python, with its own global state, is created. That global state is not shared, so changes made by child processes to global variables will be invisible to the parent process.
此外,multiprocessing
提供的大多数抽象都使用pickle来传输数据.使用代理传输的所有数据必须是可腌制的;包括 Manager
提供的所有对象.相关语录(我的重点):
Additionally, most of the abstractions that multiprocessing
provides use pickle to transfer data. All data transferred using proxies must be pickleable; that includes all the objects that a Manager
provides. Relevant quotations (my emphasis):
并且(在Manager
部分中):
Queue
也需要可腌制的数据;文档没有这么说,但是经过快速测试可以证实这一点:
Queue
s also require pickleable data; the docs don't say so, but a quick test confirms it:
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()
输出:
$ python mp.py
got pickled
got unpickled
<__main__.Thing object at 0x10056b350>
可能对您有用的一种方法是,如果您确实无法腌制数据,则是找到一种将其存储为ctype
对象的方法.然后可以传递给子进程 .对我来说这似乎很狡猾.我没做过但这可能是您可能的解决方案.
The one approach that might work for you, if you really can't pickle the data, is to find a way to store it as a ctype
object; a reference to the memory can then be passed to a child process. This seems pretty dodgy to me; I've never done it. But it might be a possible solution for you.
鉴于您的更新,看来您需要进一步了解LORR
的内部构造. LORR
是一堂课吗?您可以从中继承吗?它是其他东西的子类吗?它的MRO是多少? (尝试LORR.__mro__
并在可行的情况下发布输出.)如果它是纯python对象,则可能可以将其子类化,创建__setstate__
和__getstate__
以启用酸洗.
Given your update, it seems like you need to know a lot more about the internals of a LORR
. Is LORR
a class? Can you subclass from it? Is it a subclass of something else? What's its MRO? (Try LORR.__mro__
and post the output if it works.) If it's a pure python object, it might be possible to subclass it, creating a __setstate__
and a __getstate__
to enable pickling.
另一种方法可能是弄清楚如何从LORR
实例中获取相关数据,并通过简单的字符串将其传递.既然您说您确实只是想调用对象的方法,为什么不使用Queue
来回发送消息呢?换句话说,是这样的(示意性地):
Another approach might be to figure out how to get the relevant data out of a LORR
instance and pass it via a simple string. Since you say that you really just want to call the methods of the object, why not just do so using Queue
s to send messages back and forth? In other words, something like this (schematically):
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
这篇关于多处理全局变量更新未返回给父级的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!