如何使这个寻星器并行运行

时间:2010-08-13 21:27:01

标签: multithreading parallel-processing primes

我知道主要发现得到了很好的研究,并且有很多不同的实现。我的问题是,使用提供的方法(代码示例),我该如何分解工作?它将运行的机器有4个四核超线程处理器和16GB内存。我意识到可以做出一些改进,特别是在IsPrime方法中。我也知道,一旦列表中的项目超过int.MaxValue,就会出现问题。我不关心任何这些改进。我唯一关心的是如何分解工作。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Prime
{
    class Program
    {
        static List<ulong> primes = new List<ulong>() { 2 };

        static void Main(string[] args)
        {
            ulong reportValue = 10;
            for (ulong possible = 3; possible <= ulong.MaxValue; possible += 2)
            {
                if (possible > reportValue)
                {
                    Console.WriteLine(String.Format("\nThere are {0} primes less than {1}.", primes.Count, reportValue));

                    try
                    {
                        checked
                        {
                            reportValue *= 10;
                        }
                    }
                    catch (OverflowException)
                    {
                        reportValue = ulong.MaxValue;
                    }
                }

                if (IsPrime(possible))
                {
                    primes.Add(possible);
                    Console.Write("\r" + possible);
                }
            }

            Console.WriteLine(primes[primes.Count - 1]);
            Console.ReadLine();
        }

        static bool IsPrime(ulong value)
        {
            foreach (ulong prime in primes)
            {
                if (value % prime == 0) return false;
                if (prime * prime > value) break;
            }

            return true;
        }
    }
}

我看到有两种基本方案:1)使用所有线程来测试单个数字,这对于更高的素数可能很好,但我不能真正想到如何实现它,或者2)使用每个线程来测试单个可能的素数,当下一个要测试的数字大于找到的最高素数的平方时,可能导致找到非连续的素数串并遇到未使用的资源问题。

对我而言,感觉这两种情况只是在构建素数列表的早期阶段才具有挑战性,但我并不完全确定。这是为了打破这种工作的个人练习。

2 个答案:

答案 0 :(得分:1)

如果需要,可以将两个操作并行化:检查素数,并立即检查多个素数。虽然我不确定这会有所帮助。说实话,我会考虑删除main()中的线程。

我试图保持对你的算法的忠诚,但是为了加快它的速度,我使用了x * x而不是reportvalue;如果你愿意,这是你可以轻易恢复的东西。

为了进一步改进我的核心拆分,您可以确定一种算法,根据数字的大小计算执行拆分所需的计算次数,并以此方式拆分列表。 (又名较小的数字需要较少的时间来划分,所以使第一个分区变大)

我的线程池概念可能不会以我想要的方式存在

这是我的去处(伪代码):

List<int> primes = {2};  
List<int> nextPrimes = {};
int cores = 4;
main()
{   
  for (int x = 3; x < MAX; x=x*x){  
    int localmax = x*x;
    for(int y = x; y < localmax; y+=2){  
      thread{primecheck(y);}
    }
  "wait for all threads to be executed"
  primes.add(nextPrimes);
  nextPrimes = {};
  }
}

void primecheck(int y)
{  
  bool primality;  
  threadpool? pool;
  for(int x = 0; x < cores; x++){
    pool.add(thread{
      if (!smallcheck(x*primes.length/cores,(x+1)*primes.length/cores ,y)){
        primality = false;
        pool.kill();
      }
    });
  }  
  "wait for all threads to be executed or killed"
  if (primality)
    nextPrimes.add(y);  
}

bool smallcheck(int a, int b, int y){  
  foreach (int div in primes[a to b])  
    if (y%div == 0)  
      return false;  
  return true;
}

E:我添加了我认为合并应该是什么样的内容,如果你想在没有它的情况下查看修订版。

答案 1 :(得分:0)

使用Eratosthenes的筛子代替。除非你首先使用一个好的算法,否则不值得并行化。

将空间分隔成大的区域,并在每个筛网中筛分。或者更好地为大区域使用一些工作区概念。

使用位数组来表示素数,它比显式表示它们所占用的空间更少。

另见this answer筛选的良好实施(在Java中,不分成区域)。