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的灵活和强大。

浙公网安备 33010602011771号