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

Python多进程大数据集评估问题:共享变量未更新

问题描述

处理大量数据时改用multiprocessing实现,但共享变量max_value与best_combination始终无法更新,锁机制似乎未生效。脚本逻辑为:生成并筛选组合、按1000条分块、多进程评估,当组合value总和大于当前最大值时更新共享变量。

原代码
import itertools
from timeit import default_timer as timer
from math import factorial
from multiprocessing import Process, Value, Pool, Manager, Lock

def total_combo(n, r):
    return factorial(n) // factorial(r) // factorial(n-r)

def iterator_slice(iterator, length):
    iterator = iter(iterator)
    while True:
        res = tuple(itertools.islice(iterator, length))
        if not res:
            break
        yield res

def evaluate_combination(combinations, best_combination, max_value, lock):
           
    for combination in combinations:
        #total_index = sum(people['index'] for people in combination)
        total_value = sum(people['value'] for people in combination)
        
        # Check if the combination meets the constraints
        if total_value > max_value.value:
            with lock:
                best_combination = list(combination)
                max_value.value = total_value

def generate_filtered_combinations(players,r):
    return itertools.filterfalse(lambda y: sum(x['index'] for x in y) > 30, itertools.combinations(players, r))

if __name__ == "__main__":
    
    start = timer()
    
    # Example usage
    players = [
        {"people":"John Doe1","index":8,"value":15},
        {"people":"John Doe2","index":7,"value":28},
        {"people":"John Doe3","index":6,"value":13},
        {"people":"John Doe4","index":7,"value":11},
        {"people":"John Smith1","index":7,"value":11},
        {"people":"John Smith2","index":6,"value":9},
        {"people":"John Smith3","index":6,"value":10},
        # .... just some data for example
    ];
    
    manager = Manager()
        
    max_value = manager.Value('i', 0)
    best_combination = manager.list()
    lock = Lock()
       
    for r in range(6,8):
        print(r, total_combo(len(players),r)) # max possible items in the combination for r with players
        combos = generate_filtered_combinations(players,r) # generate all combinations filtered
              
        pool = Pool(4)  # lets use 4 workers
        cursor_iterator = iterator_slice(combos, 1000)  # slice it
        queue = []  # a queue for our current worker async results, a deque would be faster
        
        while cursor_iterator or queue:  # while we have anything to do...
            try:
                # add our next slice to the pool:
                queue.append(pool.apply_async(evaluate_combination, [next(cursor_iterator), best_combination, max_value, lock]))
            except (StopIteration, TypeError):  # no more data, clear out the slice iterator
                cursor_iterator = None
            # wait for a free worker or until all remaining finish
            while queue and (len(queue) >= pool._processes or not cursor_iterator):
                process = queue.pop(0)  # grab a process response from the top
                if not process.ready():  # a sub-process has not finished execution
                    queue.append(process)  # add it back to the queue
                else:
                    # you can use process.get() to get the result if needed
                    pass
        pool.close()
        
    # Print the best combination
    for people in best_combination:
        print(people['people'],people['index'])
    
    print(max_value.value)

    end = timer()
    print(end - start)
问题分析与修复

1. best_combination赋值错误

原代码中best_combination = list(combination)是给函数内的本地变量重新赋值,并未修改Manager创建的共享列表。正确做法是清空共享列表后替换为新组合:

with lock:
    best_combination[:] = list(combination)
    max_value.value = total_value

2. 锁未跨进程生效

普通Lock()创建的锁仅在当前进程内有效,Pool的子进程无法共享该锁。需用Manager.Lock()创建跨进程锁:

lock = manager.Lock()  # 替换原有的lock = Lock()

3. 存在竞态条件

原代码先判断total_value > max_value.value再加锁,可能在判断与加锁之间,其他进程已更新max_value,导致错误覆盖。应在加锁后重新检查:

for combination in combinations:
    total_value = sum(people['value'] for people in combination)
    with lock:
        if total_value > max_value.value:
            best_combination[:] = list(combination)
            max_value.value = total_value
修改后的完整代码
import itertools
from timeit import default_timer as timer
from math import factorial
from multiprocessing import Pool, Manager

def total_combo(n, r):
    return factorial(n) // factorial(r) // factorial(n-r)

def iterator_slice(iterator, length):
    iterator = iter(iterator)
    while True:
        res = tuple(itertools.islice(iterator, length))
        if not res:
            break
        yield res

def evaluate_combination(combinations, best_combination, max_value, lock):
    for combination in combinations:
        total_value = sum(people['value'] for people in combination)
        # 加锁后检查并更新,避免竞态条件
        with lock:
            if total_value > max_value.value:
                best_combination[:] = list(combination)
                max_value.value = total_value

def generate_filtered_combinations(players,r):
    return itertools.filterfalse(lambda y: sum(x['index'] for x in y) > 30, itertools.combinations(players, r))

if __name__ == "__main__":
    start = timer()
    
    players = [
        {"people":"John Doe1","index":8,"value":15},
        {"people":"John Doe2","index":7,"value":28},
        {"people":"John Doe3","index":6,"value":13},
        {"people":"John Doe4","index":7,"value":11},
        {"people":"John Smith1","index":7,"value":11},
        {"people":"John Smith2","index":6,"value":9},
        {"people":"John Smith3","index":6,"value":10},
        # .... just some data for example
    ]
    
    manager = Manager()
    max_value = manager.Value('i', 0)
    best_combination = manager.list()
    # 使用Manager创建跨进程锁
    lock = manager.Lock()
       
    for r in range(6,8):
        print(r, total_combo(len(players),r))
        combos = generate_filtered_combinations(players,r)
              
        pool = Pool(4)
        cursor_iterator = iterator_slice(combos, 1000)
        queue = []
        
        while cursor_iterator or queue:
            try:
                queue.append(pool.apply_async(evaluate_combination, [next(cursor_iterator), best_combination, max_value, lock]))
            except (StopIteration, TypeError):
                cursor_iterator = None
            while queue and (len(queue) >= pool._processes or not cursor_iterator):
                process = queue.pop(0)
                if not process.ready():
                    queue.append(process)
                else:
                    pass
        pool.close()
        pool.join()  # 等待进程池所有任务完成
        
    # 输出结果
    print("最佳组合:")
    for people in best_combination:
        print(people['people'], people['index'])
    print(f"最大value总和:{max_value.value}")
    
    end = timer()
    print(f"耗时:{end - start:.2f}秒")

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 08:36:59