这可能是Python中最快的质数计算方案 Python 质数计算 素数计算 多进程 多线程 超高速并行计算

9 篇文章 0 订阅
8 篇文章 0 订阅

这可能是Python中最快的质数计算方案:

穷举2亿内质数只要1秒!
穷举10亿内质数只要4.4秒!
这个速度可能比不了C,
但是对于Python可以说是非常快了!

筛选法简直无敌

从筛选法单线程实现,单线程结果保存,
到多进程实现,结果分段保存,自动合并
再到边计算边合并, 最后整理代模块化
一下搞了将近20个小时…

上结果!

穷举2亿内质数 ↓

在这里插入图片描述

穷举10亿内质数↓

在这里插入图片描述

以下是代码:

# -*- coding = utf-8 -*-
# @Time : 2020/9/8 20:43
# @Author : Suage
# @File : 找质数_火力全开.py
import time
import concurrent.futures
import numpy


class FindPrimeNumber:
    def __init__(self, block_size, core_num):
        self.block_size = block_size
        self.core_num = core_num
        self.upper = None

    def find_prime(self, upper):
        prime_list = []
        mid = int(numpy.sqrt(upper))
        nums = numpy.arange(upper)
        nums[1] = 0
        while True:
            primes = nums[nums > 0]
            if primes.any():
                p = primes[0]
                prime_list.append(p)
                nums[p::p] = 0
                if p > mid:
                    break
            else:
                break
        prime_list.extend(nums[nums > 0].tolist())
        return prime_list

    def fast_find_prime(self, upper, base=None):
        self.upper = upper
        if base is None:
            base = int(numpy.sqrt(self.upper)) + 1

        if self.upper <= base:
            return self.find_prime(self.upper)

        self.prime_list = self.find_prime(base)

        self.base_prime_array = numpy.array(self.prime_list)

        print('Create task list', end='...')
        task_base_prime_array_list = []
        task_range_list = []
        start = base
        while start < self.upper:
            end = start + self.block_size
            if end > self.upper:
                end = self.upper
            mid = numpy.sqrt(end)
            base = self.base_prime_array[self.base_prime_array <= mid]
            task_base_prime_array_list.append(base)
            task_range_list.append((start, end))
            start += self.block_size
        print('OK!')

        with concurrent.futures.ProcessPoolExecutor(max_workers=self.core_num) as executor:
            returns = executor.map(self.process_func,
                                   zip(task_base_prime_array_list, task_range_list))

        print('合并计算结果...')
        for r in returns:
            self.prime_list.extend(r)

    def process_func(self, params):
        primes, task_range = params[0], params[1]
        nums = numpy.arange(task_range[0], task_range[1])
        for p in primes:
            k = (p - task_range[0] % p) % p
            nums[k::p] = 0

        print(
            f'{task_range[1]:0=15d} be checked! Progress:{task_range[1] / self.upper:5.2%}')
        return nums[nums > 0].tolist()


if __name__ == '__main__':
    # 以下两项根据自己的配置修改
    block_size = 500000  # i9-9900k(500000)
    core_num = 8  # 处理器物理核心数(非线程数) i9-9900k(8)

    upper = int(input('计算终点:')) + 1
    # upper = 100000000 + 1
    t0 = time.time()
    fpn = FindPrimeNumber(block_size=block_size,
                          core_num=core_num)
    fpn.fast_find_prime(upper)
    print('*' * 50)
    print('OK!')
    print(f'{upper - 1}以内的质数计算耗时{time.time() - t0:0.2f}秒')
    print(f'计{len(fpn.prime_list)}个')

结果保存至文件的代码:

# -*- coding = utf-8 -*-
# @Time : 2020/9/8 20:43
# @Author : Suage
# @File : 找质数_火力全开.py
from shutil import rmtree
from os import rename, listdir, remove, path, makedirs
import re
import threading
import time
import concurrent.futures
import numpy


class MergeFile(threading.Thread):
    def set_show_merge_progress_to_true(self):
        self.show_merge_progress = True

    def run(self):
        self.show_merge_progress = False
        result_prime_nums_file = open(f'{save_path}/PrimeNum.txt', 'w')
        re_rules = '_(\d{15})~(\d{15})_'
        next_file_start_index = 2
        can_not_find_next_file = False
        while True:
            if can_not_find_next_file:
                time.sleep(0.1)
            can_not_find_next_file = True
            for f in listdir(save_path):
                if f'PrimeNum_{next_file_start_index:0=15d}~' in f:
                    find_file_name = f
                    file_name_research = re.search(re_rules, find_file_name)
                    if self.show_merge_progress:
                        print(
                            f'Merge progress:'
                            f'{int(file_name_research.group(1)) / upper:5.2%}')
                    next_file_start_index = int(file_name_research.group(2)) + 1
                    temp_file = open(f'{save_path}/{find_file_name}', 'r')
                    result_prime_nums_file.write(temp_file.read())
                    temp_file.close()
                    remove(f'{save_path}/{find_file_name}')
                    can_not_find_next_file = False
                    if next_file_start_index == 1:
                        result_prime_nums_file.close()
                        return
                    break


class FindPrimeNumber:
    def __init__(self, save_path, block_size, core_num):
        self.save_path = save_path
        self.block_size = block_size
        self.core_num = core_num
        self.upper = None

    def find_prime(self, upper):
        prime_list = []
        mid = int(numpy.sqrt(upper))
        nums = numpy.arange(upper)
        nums[1] = 0
        while True:
            primes = nums[nums > 0]
            if primes.any():
                p = primes[0]
                prime_list.append(p)
                nums[p::p] = 0
                if p > mid:
                    break
            else:
                break
        prime_list.extend(nums[nums > 0].tolist())
        return prime_list

    def fast_find_prime(self, upper, base=None):
        self.upper = upper
        if base is None:
            base = int(numpy.sqrt(self.upper)) + 1

        if self.upper <= base:
            return self.find_prime(self.upper)

        self.prime_list = self.find_prime(base)

        with open(f'{self.save_path}/PrimeNum_{2:0=15d}~{base - 1:0=15d}_preparation.pn',
                  'w',
                  encoding='utf-8') as file:
            file.write(
                str(self.prime_list)[1:-1].replace(' ', '')
            )
            file.write(',')
            file.close()
        rename(f'{self.save_path}/PrimeNum_{2:0=15d}~{base - 1:0=15d}_preparation.pn',
               f'{self.save_path}/PrimeNum_{2:0=15d}~{base - 1:0=15d}_complete.pn')

        self.base_prime_array = numpy.array(self.prime_list)

        print('Create task list', end='...')
        task_base_prime_array_list = []
        task_range_list = []
        start = base
        while start < self.upper:
            end = start + self.block_size
            if end > self.upper:
                end = self.upper
            mid = numpy.sqrt(end)
            base = self.base_prime_array[self.base_prime_array <= mid]
            task_base_prime_array_list.append(base)
            task_range_list.append((start, end))
            start += self.block_size
        print('OK!')

        with concurrent.futures.ProcessPoolExecutor(max_workers=self.core_num) as executor:
            executor.map(self.process_func,
                         zip(task_base_prime_array_list, task_range_list))

        with open(f'{self.save_path}/PrimeNum_{self.upper:0=15d}~'
                  f'{0:0=15d}_complete.pn', 'w') as end_mark:
            end_mark.close()

    def process_func(self, params):
        primes, task_range = params[0], params[1]
        nums = numpy.arange(task_range[0], task_range[1])
        for p in primes:
            k = (p - task_range[0] % p) % p
            nums[k::p] = 0

        with open(f'{self.save_path}/PrimeNum_{task_range[0]:0=15d}~'
                  f'{task_range[1] - 1:0=15d}_preparation.pn',
                  'w',
                  encoding='utf-8') as file:
            file.write(
                str(nums[nums > 0].tolist())[1:-1].replace(' ', '')
            )
            file.write(',')
            file.close()
        rename(f'{self.save_path}/PrimeNum_{task_range[0]:0=15d}~'
               f'{task_range[1] - 1:0=15d}_preparation.pn',
               f'{self.save_path}/PrimeNum_{task_range[0]:0=15d}~{task_range[1] - 1:0=15d}'
               f'_complete.pn')
        print(
            f'{task_range[1]:0=15d} be checked! Progress:{task_range[1] / self.upper:5.2%}')


if __name__ == '__main__':
    # 用于保存计算结果(最后不要斜杠)
    save_path = './prime_out' # 此目录会被清空,请注意!
    # 以下两项根据自己的配置修改
    block_size = 500000  # i9-9900k(500000)
    core_num = 8  # 处理器物理核心数(非线程数) i9-9900k(8)

    if path.exists(save_path):
        rmtree(save_path)
    makedirs(save_path)
    mf = MergeFile()

    upper = int(input('计算终点:')) + 1
    # upper = 100000000 + 1
    t0 = time.time()
    mf.start()
    fpn = FindPrimeNumber(save_path=save_path,
                          block_size=block_size,
                          core_num=core_num)
    fpn.fast_find_prime(upper)
    print('*' * 50)
    mf.set_show_merge_progress_to_true()
    mf.join()
    print('*' * 50)
    print('OK!')
    print(f'{upper - 1}以内的质数计算耗时{time.time() - t0:0.2f}秒')

感谢一位大佬, 学来了筛选法, 想贴出来的, 但是代码写完了之前看的页面找不到了…

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值