【问题标题】:Python generator and set(generator) get different resultsPython 生成器和 set(generator) 得到不同的结果
【发布时间】:2018-03-07 10:43:19
【问题描述】:

我有如下代码

def yield_multiple():
    for prime in prime_list:
        for multiple in range(prime+prime, end, prime):
            yield multiple

我用它来获取素数

multiple_set = set(yield_multiple())
result = [v for v in candidate_list if v not in multiple_set]

而且我在set很大的时候遇到内存错误,所以想用这个来节省内存

result = [v for v in candidate_list if v not in yield_multiple()]

但这会得到错误的结果。那么,如何避免内存错误以正确获取素数呢?

这是我改进的解决方案,没有太多内存可供使用。

import math
import sys

import time
from mpi4py import MPI

import eratosthenes

comm = MPI.COMM_WORLD
rank = comm.Get_rank()
size = comm.Get_size()

TAG_RESULT = 0

n = sys.argv[1]
if n.isdigit():
    start_time = time.time()
    n = int(n)
    sqrt_n = int(math.sqrt(n))

    task_per_block = int(math.ceil((n - 1) / size))
    begin = 2 + rank * task_per_block
    end = begin + task_per_block if begin + task_per_block <= n + 1 else n + 1
    if rank == 0:
        begin = sqrt_n if sqrt_n < end else begin
    sieve_list = [True] * (end - begin)
    prime_list = eratosthenes.sieve(sqrt_n)

    if rank == 0:
        result = sum(prime_list)
        for prime in prime_list:
            start = begin if begin % prime == 0 else (int(begin / prime) + 1) * prime
            for multiple in range(start, end, prime):
                sieve_list[multiple - begin] = False
        result += sum(i + begin for i, v in enumerate(sieve_list) if v)
        result_received = 0
        while result_received < size - 1:
            data = comm.recv(source=MPI.ANY_SOURCE, tag=TAG_RESULT)
            result += data
            result_received += 1
        print(result)
        print(time.time() - start_time)
    else:
        for prime in prime_list:
            start = begin if begin % prime == 0 else (int(begin / prime) + 1) * prime
            for multiple in range(start, end, prime):
                sieve_list[multiple - begin] = False
        result = sum(i + begin for i, v in enumerate(sieve_list) if v)
        comm.send(result, dest=0, tag=TAG_RESULT)

【问题讨论】:

  • 当您尝试提取素数时,为什么要使用for multiple in range(prime, end, prime)?您可能想看看 Sieve 或 Eratosthenes 算法。
  • @cᴏʟᴅsᴘᴇᴇᴅ 是的,我知道埃拉托色尼筛。但我试图做一个扰乱版的埃拉托色尼筛。所以这是获得给定范围内所有倍数的好方法
  • 对于分布式筛子,您可能需要合并树中的多个流,例如喜欢the one here
  • @WillNess 你是对的。应该是for multiple in range(prime+prime, end, prime)
  • @WillNess 我现在有了更好的解决方案。你可以在上面检查它。当我使用 48 核时,它会比单核快 20 倍

标签: python concurrency parallel-processing primes sieve-of-eratosthenes


【解决方案1】:

通过在连续素数的平方之间切换到分段工作,为每个分段一个接一个地创建这些集合。

对于每个段,您必须计算枚举素数倍数的起点,每个已知素数不大于该段的最高值(即下一个 "core"素数平方)。

“核心”素数,要得到平方,你可以通过相同算法的递归应用分别独立地得到。

这种方法的一个例子(即单独的素数供应)是How to implement an efficient infinite generator of prime numbers in Python?

要使其并行,您需要找到在所有枚举之间以共享方式使用集合的方法,每个枚举都将设置其每个枚举倍数关闭 em> 在同一个共享集中。操作顺序并不重要,只要它们都完成即可。不需要保护访问,因为将相同的位置 off 设置两次(或更多)就可以了。

这也将非常有效。

【讨论】:

    【解决方案2】:

    如果您想继续使用这种方法——它确实有一定的简单性,尽管它一定是非常低效的——我能看到的最简单的方法是无需为每个候选人构建一个大集合或重新运行 yield_multiple是为了扭转您的会员资格检查:

    multiples = {c for c in yield_multiple() if c in candidate_list}
    result = [c for c in candidate_list if c not in multiples]
    

    但是,除非使用您自己的代码是这里最重要的因素,否则我建议您找到一种更有效的方法,例如 in this other answer 中描述的方法。

    【讨论】:

    • 抱歉误导了各位。我不想找到一种更快的方法来获得质数。这是我的并行编程课程。基本上,我试图与埃拉托色尼筛法平行。我应该开始另一个问题。
    • @BlaiseWang 不需要。我编辑了你问题的标签。
    猜你喜欢
    • 1970-01-01
    • 2021-02-18
    • 2017-10-01
    • 2023-03-19
    • 1970-01-01
    • 2019-09-26
    • 1970-01-01
    • 2019-01-06
    • 1970-01-01
    相关资源
    最近更新 更多