CSP和埃氏筛

埃氏筛的基本原理

  • 数学上指在大于1的整数中只能被1和它本身整除的数,为质数
  • 合数必定可以化作多个质数的乘积,如果因数是合数,总是可以继续拆分
  • 因此,如果一个数不能被比它小的所有质数整除,那么它也是一个质数。

其他

  • 哥德巴赫猜想:每一个大于2的偶数是两个质数的和

Go语言版本

package main

import (
	"context"
	"fmt"
	"time"
)

func generateBuffered(ctx context.Context, bufferSize int) chan int {
	out := make(chan int, bufferSize)
	go func() {
		defer close(out)
		for i := 2; ; i++ {
			select {
			case <-ctx.Done():
				return // benchmarkPrimes退出时, 关闭生成器
			case out <- i:
			}
		}
	}()
	return out
}

func filterBuffered(in chan int, prime int, bufferSize int) chan int {
	out := make(chan int, bufferSize)
	go func() {
		defer close(out)
		for i := range in { // 上游通道关闭时, for range结束, 关闭通道
			if i%prime != 0 {
				out <- i
			}
		}
	}()
	return out
}

func benchmarkPrimes(bufferSize int) time.Duration {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	start := time.Now()

	ch := generateBuffered(ctx, bufferSize)
	for i := 0; i < 20000; i++ {
		prime := <-ch
		ch = filterBuffered(ch, prime, bufferSize)
	}

	elapsed := time.Since(start)
	return elapsed
}

func main() {
	for _, size := range []int{0, 10, 100, 1000} {
		duration := benchmarkPrimes(size)
		fmt.Printf("Buffer size %d: %s\n", size, duration)
	}
}

Buffer size 0: 3.861149625s
Buffer size 10: 2.821489375s
Buffer size 100: 2.431522292s
Buffer size 1000: 2.286453s

执行耗时有一定的随机性,大部分情况下size 10和100性能最好

Java虚拟线程版本

package org.example;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ArrayBlockingQueue;

public class VirtualThreadSieve {
    static final int CAPACITY = 20;

    // 用于生成自然数
    static BlockingQueue<Integer> startNumberGenerator() {
        BlockingQueue<Integer> origin = new ArrayBlockingQueue<>(CAPACITY);
        Thread.startVirtualThread(() -> {
            for (int i = 2; ; i++) {
                try {
                    origin.put(i);
                } catch (InterruptedException _) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        });
        return origin;
    }

    // 过滤器线程:去掉能被 prime 整除的数
    static BlockingQueue<Integer> createFilteredQueue(BlockingQueue<Integer> input, int prime) {
        BlockingQueue<Integer> output = new ArrayBlockingQueue<>(CAPACITY);
        Thread.startVirtualThread(() -> {
            while (true) {
                try {
                    int num = input.take();
                    if (num % prime != 0) output.put(num);
                } catch (InterruptedException _) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        });
        return output;
    }

    void main() throws InterruptedException {
        long start = System.currentTimeMillis();
        var base = startNumberGenerator(); // 产生 2,3,4,...
        for (int i = 0; i < 20000; i++) {
            int prime = base.take(); // 当前质数
            base = createFilteredQueue(base, prime);
        }
        System.out.printf("Elapsed time %fs", (System.currentTimeMillis() - start) / 1_000.0);
    }
}

Elapsed time 17.646000s

ArrayBlockingQueue(利用ReentrantLock)相较go语言的chan性能较弱(环形数组 + 显式锁 vs 环形队列 + 调度器协调(无锁)),是主要性能瓶颈。

Python异步版本

import asyncio
from typing import AsyncIterator


async def generate_numbers() -> asyncio.Queue:
    output = asyncio.Queue(maxsize=1000)
    async def produce():
        n = 2
        while True:
            await output.put(n)
            n += 1
    asyncio.create_task(produce())
    return output


async def filter_primes(input_q: asyncio.Queue, prime: int) -> asyncio.Queue:
    output_q = asyncio.Queue(maxsize=1000)
    async def filter_loop():
        while True:
            num = await input_q.get()
            if num % prime != 0:
                await output_q.put(num)
    asyncio.create_task(filter_loop())
    return output_q


async def sieve() -> AsyncIterator[int]:
    """高性能异步埃氏筛"""
    q = await generate_numbers()

    while True:
        prime = await q.get()
        yield prime
        q = await filter_primes(q, prime)


async def main():
    """测试性能"""
    count = 0
    start_time = asyncio.get_event_loop().time()
    async for prime in sieve():
        # print(prime, end=" ", flush=True)
        count += 1
        if count >= 10_000:  # 生成10,000个素数后退出
            break
    elapsed = asyncio.get_event_loop().time() - start_time
    print(f"\nGenerated {count} primes in {elapsed:.2f} seconds")


if __name__ == "__main__":
    asyncio.run(main())

Generated 10000 primes in 117.01 seconds

性能很差

Python生成器版本

import time


def generate_numbers():
    n = 2
    while True:
        yield n
        n += 1


def sieve():
    numbers = generate_numbers()
    while True:
        prime = next(numbers)
        yield prime
        numbers = filter(lambda x, p=prime: x % p != 0, numbers)


if __name__ == '__main__':
    start_time = time.time()
    primes = sieve()
    for _ in range(20000):
        next(primes)
        # print(next(primes))
    print(f"Time taken: {time.time() - start_time:.4f} seconds")

Time taken: 10.6330 seconds

充分体现了Python的generator的灵活和强大。

posted @ 2025-07-07 11:07  又是火星人  阅读(14)  评论(0)    收藏  举报