Python生成器和set(生成器)得到不同的结果

时间:2018-03-07 10:43:19

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

我的代码如下

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]

当设置非常大时,我遇到内存错误,所以我想用它来保存内存

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)

2 个答案:

答案 0 :(得分:1)

通过切换到连续素数的平方之间的片段,逐个为每个片段创建这些集合。

对于每个段,您必须计算素数倍数的枚举的起始点,对于每个已知素数不大于段的最高值(即下一个“核心”素数广场)。

“核心”素数,为了获得平方,您可以通过递归应用相同的算法来单独获得。

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

要使其成为 parallel ,您需要找到在所有枚举之间以共享方式使用该集合的方法,每个枚举都会设置每个枚举倍数 off 在同一个共享集中。操作顺序并不重要,只要它们都已完成。无需保护访问权限,因为设置相同的位置关闭两次(或更多)完全没问题。

这也非常有效。

答案 1 :(得分:0)

如果你想继续使用这种方法 - 它确实有一定的简单性,尽管它必须非常低效 - 我可以看到这样做的最简单方法,无需构建大型集合或重新运行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所描述的方法。