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

牌组洗牌与分析的并行化优化方案咨询

提升牌组洗牌与分析流程的运行效率

首先,你的代码已经尝试了ProcessPoolExecutor并行化,但未达到预期效果。下面从瓶颈定位、并行化修复、效率优化三个维度给出具体解决方案:

1. 先定位核心性能瓶颈

并行化仅对CPU/计算密集型任务有效,先明确哪一步最耗时:
在shuffle_and_solve中加入计时代码,拆分各环节耗时:

import time
import os

def shuffle_and_solve(_):
    print(f"当前进程ID: {os.getpid()}") # 验证是否多进程运行
    start = time.time()
    cards = [(i, j) for i in '23456789TJQKA' for j in 'CDHS']
    shuffle(cards)
    print(f"洗牌耗时: {time.time() - start:.4f}s")
    
    start = time.time()
    result = prettysolve(cards)
    print(f"求解+格式化耗时: {time.time() - start:.4f}s")
    return cards, result

如果solve(即ddstable.get_ddstable)占总耗时90%以上,说明并行化方向正确;若其他步骤占比高,优先优化这些环节。

2. 修复并行化不生效问题

2.1 确认多进程真的在运行

运行上述代码,若输出的进程ID全部相同,说明并行未启动:

  • 检查num_decks是否大于1;
  • 确保所有进程相关代码被if __name__ == '__main__':包裹(你的代码已满足)。

2.2 避免子进程重复加载库

每个子进程会重新初始化环境,若ddstable加载成本高,会浪费大量时间。用initializer提前在每个子进程加载一次:

def init_worker():
    global solve
    from ddstable import ddstable
    solve = ddstable.get_ddstable

if __name__ == '__main__':
    num_decks = 16
    # 指定进程数为CPU核心数(默认也是这个值,可手动调整)
    with concurrent.futures.ProcessPoolExecutor(initializer=init_worker) as executor:
        futures = [executor.submit(shuffle_and_solve, _) for _ in range(num_decks)]
        outputs = [future.result() for future in concurrent.futures.as_completed(futures)]

2.3 减少进程间数据传输开销

shuffle_and_solve返回的cards和result需要序列化后传给主进程,若不需要cards可直接省略;若必须保存,尽量精简返回数据的体积。

3. 进一步提升运行效率

3.1 批量处理任务

单任务处理一个牌组的调度、序列化开销相对较高,改为一次处理多个牌组:

def shuffle_and_solve_batch(batch_size):
    results = []
    # 预生成基础牌组,避免重复创建
    base_cards = [(i, j) for i in '23456789TJQKA' for j in 'CDHS']
    for _ in range(batch_size):
        cards = base_cards.copy()
        shuffle(cards)
        result = prettysolve(cards)
        results.append((cards, result))
    return results

if __name__ == '__main__':
    total_decks = 16
    num_workers = os.cpu_count()
    decks_per_worker = total_decks // num_workers
    
    with concurrent.futures.ProcessPoolExecutor(max_workers=num_workers, initializer=init_worker) as executor:
        futures = [executor.submit(shuffle_and_solve_batch, decks_per_worker) for _ in range(num_workers)]
        # 处理剩余的牌组
        if total_decks % num_workers != 0:
            futures.append(executor.submit(shuffle_and_solve_batch, total_decks % num_workers))
        
        outputs = []
        for future in concurrent.futures.as_completed(futures):
            outputs.extend(future.result())
    
    sets, results = zip(*outputs)

3.2 优化prettysolve的字符串处理

字符串拼接用列表收集后join比逐个+=更高效,可进一步优化格式化逻辑:

def prettysolve(cards):
    lines = ["  {:>2} {:>2} {:>2} {:>2} {:>2}".format("S", "H", "D", "C", "NT")]
    all_solves = solve(bytes(PBN(cards), 'utf-8'))
    for each in all_solves:
        line_parts = [f"{each:>1}"]
        for suit in ddstable.dcardSuit:
            line_parts.append(f"{all_solves[each][suit]-6:2}")
        lines.append(" ".join(line_parts))
    return '\n'.join(lines)

3.3 调整进程数

  • 纯CPU密集型任务:设为CPU核心数即可;
  • 若solve涉及IO操作:可设为核心数的2倍,充分利用等待时间。

4. 其他潜在优化方向

  • 检查ddstable是否支持批量求解:若get_ddstable可一次性处理多个牌组的PBN字符串,直接批量调用会比单张处理效率高很多;
  • 预生成所有基础牌组:将base_cards移到全局,避免每个任务重复创建;
  • 替换并行库:若concurrent.futures仍有问题,可直接用multiprocessing模块,底层控制更精细。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 12:25:21