RAM 过载 - itertools

RAM overload - itertools

这是我正在尝试做的一个简单示例以及我遇到的错误:

    for symbol in itertools.product(list_a, repeat=8):
        list_b.append(symbol)

之后我也会从该列表中排除组合,如下所示:

    for combination in list_b:
        valid_b = True
        for symbols in range(len(list_exclude)):
            if list_exclude[symbols] in combination:
                valid_b = False
            else:
                pass
        if valid_b:
            new_list.append(combination)

我听说以某种方式将流程分块可能会有所帮助,但不确定如何在此处完成。

我也在为此使用多处理。

当我 运行 它时,我得到“MemoryError”

你会怎么做?

我所做的这个小改动可以为您节省一些 ram 使用量。

    for combination in list_b:
        valid_b = True
        for symbols in list_exclude:
            if symbols in combination:
                valid_b = False
            else:
                pass
        if valid_b:
            new_list.append(combination)

不要预先计算任何东西,尤其是第一个完整列表:

def symbols(lst, exclude):
    for symbol in map(''.join, itertools.product(lst, repeat=8)):
        if any(map(symbol.__contains__, exclude)):
            continue
        yield symbol

现在使用生成器,因为您需要延迟计算元素。请记住,由于它是对数据进行预过滤,因此即使 list(symbols(list_a, list_exclude)) 也会比您最初写的便宜得多。

这里是发生了什么的细目:

  • itertools.product 是一个生成器。这意味着它在不保留对任何先前项目的引用的情况下生成输出。它 returns 的每个元素都是 tuple 包含输入元素的某种组合。

  • 既然要比较字符串,就需要对tuple进行转换。因此,''.join。将其映射到 itertools.product 生成的每个 tuple 将这些元素转换为字符串。例如:

    >>> ''.join(('$', '$', '&', '&', '♀', '@', '%', '$'))
    '$$&&♀@%$'
    
  • 过滤每个如此创建的 symbol 可以通过检查是否包含 excludes 中的任何项目来完成。你可以用

    之类的东西来做到这一点
    [ex in symbol for ex in exclude]
    

    操作... in symbol是通过魔术方法symbol.__contains__实现的。因此,您可以 map 该方法用于 exclude.

    的每个元素
  • 由于symbol中包含的exclude的第一个元素使它无效,所以不需要检查余数。这称为短路,并在 any 函数中实现。请注意,因为 map 是一个生成器,所以一旦找到匹配项,实际上将不会计算剩余的元素。这与使用列表理解不同,后者预先计算所有元素。

  • yield 放入您的函数中会将其变成生成器函数。这意味着当您调用 symbols(...) 时,它 returns 是一个您可以迭代的生成器对象。在您对其调用 next 之前,该对象不会预先计算任何内容。因此,如果您将数据写入文件(例如),那么只有当前结果会立即进入内存。写出大量结果可能需要很长时间,但您的内存使用量不应因此而飙升。