You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python multiprocessing中列表推导式传入列表无法更新问题咨询

多进程下列表推导式生成的列表无法更新字典值的问题

当使用multiprocessing模块时,通过列表推导式生成的列表传入函数后,其中字典的val2chg条目无法更新。但不使用多进程时逻辑正常,直接传入原列表而非列表推导式生成的列表时,多进程代码也能成功执行。

输入与测试场景结果

输入的原始列表sld为:

[{'val': 0, 'val2chg': 'not'}, {'val': 1, 'val2chg': 'not'}]

四种测试场景的结果:

  • multiproc: True. listcomp: True, [{'val': 0, 'val2chg': 'not'}, {'val': 1, 'val2chg': 'not'}]
  • multiproc: False. listcomp: True, [{'val': 0, 'val2chg': 'changed'}, {'val': 1, 'val2chg': 'changed'}]
  • multiproc: False. listcomp: False, [{'val': 0, 'val2chg': 'changed'}, {'val': 1, 'val2chg': 'changed'}]
  • multiproc: True. listcomp: False, [{'val': 0, 'val2chg': 'changed'}, {'val': 1, 'val2chg': 'changed'}]

测试代码

import multiprocessing as mp
sld = [{'val':0, 'val2chg':'not'}, {'val':1, 'val2chg':'not'}]
print(sld)
def update_values(sld, domp):
        global update
        def update(idx, some):
                some['val2chg'] = 'changed'
                return idx, some
        if domp:
                pool = mp.Pool()
                results = [pool.apply_async(update, (idx, sld[idx])) for idx in range(len(sld))]
                pool.close()
                pool.join()
                for result in results:
                        idx = result.get()[0]
                        sld[idx] = result.get()[1]
        else:
                for idx in range(len(sld)):
                        results = update(idx, sld[idx])
                        idx = results[0]
                        sld[idx] = results[1]
domp = True
listcomp = False
if listcomp:
        update_values([s for idx, s in enumerate(sld)], domp)
else:
        update_values(sld, domp)
print(f'multiproc: {domp}. listcomp: {listcomp}, {sld}')

问题原因与解决方法

原因分析

  1. 多进程内存隔离:Python多进程采用写时复制机制,每个子进程会复制父进程的内存空间。当你用列表推导式[s for idx, s in enumerate(sld)]生成新列表时,这个列表是主进程的临时局部变量,传入update_values后:
    • 子进程处理时会复制这个临时列表,更新操作只作用于子进程内的副本,主进程的原始sld完全不受影响。
    • 函数执行完后,临时列表被销毁,主进程自然看不到任何变化。
  2. 直接传原列表的逻辑:直接传原sld时,update_values里的赋值操作是在主进程完成的——子进程返回处理后的字典,主进程把它替换到原列表的对应位置,所以原列表能被更新。

解决方法

如果要保留列表推导式的使用,同时让主进程的原始列表得到更新,可修改代码让函数返回处理后的列表,再赋值给原sld:

  1. 修改update_values函数,在末尾添加返回语句:
def update_values(sld, domp):
        global update
        def update(idx, some):
                some['val2chg'] = 'changed'
                return idx, some
        if domp:
                pool = mp.Pool()
                results = [pool.apply_async(update, (idx, sld[idx])) for idx in range(len(sld))]
                pool.close()
                pool.join()
                for result in results:
                        idx = result.get()[0]
                        sld[idx] = result.get()[1]
        else:
                for idx in range(len(sld)):
                        results = update(idx, sld[idx])
                        idx = results[0]
                        sld[idx] = results[1]
        return sld  # 添加返回处理后的列表
  1. 修改调用逻辑,接收返回值:
if listcomp:
        sld = update_values([s for idx, s in enumerate(sld)], domp)
else:
        update_values(sld, domp)

或者直接避免使用临时的列表推导式生成列表,直接操作原列表,让主进程直接接收子进程的更新结果。

内容的提问来源于stack exchange,提问作者Schro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 05:18:17