C# 用并行算法求素数

C# 用并行算法求素数,c#,math,parallel-processing,primes,C#,Math,Parallel Processing,Primes,所以我创建了下面的方法来找到所有的素数,直到一个特定的数字。关于如何加快速度有什么建议吗 我这样称呼它; interval=(value+NOOFTHREADS-1)/NOOFTHREADS; int max=interval*NOOFTHREADS; 票证=新列表(NOOFTHREADS); for(int i=1;i findTime()); 具有一些全局变量; static List vals=new List(); 静态列表票据; 静态整数间隔=新整数(); 方法,; publi

所以我创建了下面的方法来找到所有的素数,直到一个特定的数字。关于如何加快速度有什么建议吗

我这样称呼它;
interval=(value+NOOFTHREADS-1)/NOOFTHREADS;
int max=interval*NOOFTHREADS;
票证=新列表(NOOFTHREADS);
for(int i=1;i findTime());

具有一些全局变量;
static List vals=new List();
静态列表票据;
静态整数间隔=新整数();

方法,;
publicstaticvoidfindpremes()
{
int myTicket;
锁(票)
{
myTicket=(int)tickets.Last();
tickets.RemoveAt(tickets.Count-1);
}
var max=myTicket;
int min=最大-间隔+1;
int-num;
var maxSquareRoot=Math.Sqrt(最大值);
消除的var=新的System.Collections.BitArray(最大值+1);
已消除[0]=真;
消除[1]=真;
对于(int i=2;i<(max)/2;i++)
{
如果(!消除[i])
{
if(i对于(int j=num;j有没有理由实现教科书上的数学可读平方根算法?

看一看

已经有很多关于并行与串行代码性能的文档。Microsoft建议您在将代码转换为并行体系结构之前阅读他们关于使用并行功能的文档

考虑阅读我在这里发布的以下Q/A:


我认为你所有的锁都可能有问题,你应该尽量避免使用锁,因为它们非常昂贵。我不知道你的算法的细节,但我认为你应该尝试以某种方式移除锁。这些票据可以输入?它们可以有自己的输出队列,当所有的锁都完成后,你可以合并它们?

Eratosthenes c的筛选一个程序很容易并行化,只需将其拆分为单独的块并单独筛选每个块。您已经开始进行拆分,但还没有取得好的结果。让我们看看
findTime()

您为每个线程创建一个新的
位数组
,覆盖从0到
max
的所有数字。对于筛选第一个块的线程,这很好,但对于以后的线程,您分配的内存远远超过所需的内存。由于上限很高且线程很多,这本身就是一个问题,您分配的内存大致是
(NOOFTHREADS+1)*limit/2
位,其中只需要约
limit
位。对于较少的线程和/或较低的限制,您仍在恶化局部性,并将有更多缓存未命中

eliminated[0] = true;
eliminated[1] = true;
for (int i = 2; i < (max) / 2; i++)

已消除[i]
只能在
i>=min
时为真(或
i<2
),你只会在
i的第一部分遇到这种情况,这应该是一个注释,而不是真正回答你的问题。Eratosthenes的筛选不适合进行简单的并行化。你的链接似乎离我正在做的事情没有一百万英里远。虽然我不知道c。我如何将c示例应用到我的代码中?忽略我的answer、 spender有一个很好的观点。该算法(由peoro建议)从2到一个设定的极限顺序进行。没有简单的方法从不同的位置开始几个踏板。该算法(据我所见)有O(n)复杂性,所以向你扔东西似乎是件好事。你不需要c。我的回答很傻,我真的不能帮你解决问题,对不起。你是说(根据你的第二个链接)我的结果可能不够准确?这取决于您如何测试串行循环与并行循环的性能。如果您使用.NET的Stopwatch类进行测试,您的结果将不会完全准确。为了获得最佳准确度,您需要通过探查器运行代码。并行循环并不总是适用于所有场景,有些情况下imes串行循环会更快!作为一个想法,您可以使用秒表,对代码进行多次迭代,将所有结果相加,然后除以迭代次数,这将为您提供执行时间的粗略平均值。基于第一次运行的分析不理想的原因是第一次运行时,您的代码是JIT的,因此您需要补偿JIT开销。我想知道锁是否可能是问题所在。但想不出解决它们的方法。当每个线程都开始使用相同的方法时,我如何将不同的数据输入到每个线程的方法中?据我所知,您有线程数作为输入,并且你把输入扔掉。你应该调用.AsParallel()而是在你的票证列表上。拥有固定数量的线程不是PLINQ的工作,我认为这是我得到的最好答案。我花了一段时间理解了所有的事情,但你的解释很棒。谢谢。如果我有一个问题,那就是你的方法似乎返回1作为质数。这是故意的吗?在大多数情况下,我认为1是不完整的阿德。不,这是一个疏忽。我习惯于在5或7点开始筛选,所以我不需要对1采取特别的预防措施,对不起。如果你的编辑是为了表明你想要进一步加快速度,那应该是一个新问题。但是,正常的步骤是1。从筛选中删除偶数,这是一个大约2的系数,很简单;2。eliminate也是3的倍数,这是大约1.5的另一个因数,仍然相对容易;3.消除更多小素数的倍数,随着回报率的降低,这变得越来越困难-或者使用其他人认真调整过的库,例如Kim Walisch的素数筛(C++)或Daniel Bernstein的素数筛(C)。
static List<int> vals = new List<int>();
static List<int> tickets;
static int interval = new int();
public static void findPrimes()
    {
        int myTicket;
        lock (tickets)
        {
            myTicket = (int)tickets.Last();
            tickets.RemoveAt(tickets.Count - 1);
        }
        var max = myTicket;
        int min = max - interval +1;
        int num;

        var maxSquareRoot = Math.Sqrt(max);
        var eliminated = new System.Collections.BitArray(max + 1);
        eliminated[0] = true;
        eliminated[1] = true;
        for (int i = 2; i < (max) / 2; i++)
        {
            if (!eliminated[i])
            {
                if (i < maxSquareRoot)
                {
                    num = ((min + i -1 )/i)*i;

                    if (num == i)
                        num = num + i;

                    for (int j =num; j <= max; j += i)
                        eliminated[j] = true;
                }
            }
        }
        for (int b = (int)min; b < max; b++)
        {
            if (!eliminated[b])
                lock(vals)
                    vals.Add(b);
        }
    }
var max = myTicket;
int min = max - interval +1;
int num;

var maxSquareRoot = Math.Sqrt(max);
var eliminated = new System.Collections.BitArray(max + 1);
eliminated[0] = true;
eliminated[1] = true;
for (int i = 2; i < (max) / 2; i++)
{
    if (!eliminated[i])
    {
        if (i < maxSquareRoot)
        {
            num = ((min + i -1 )/i)*i;

            if (num == i)
                num = num + i;

            for (int j =num; j <= max; j += i)
                eliminated[j] = true;
        }
    }
}
for (int b = (int)min; b < max; b++)
{
    if (!eliminated[b])
        lock(vals)
            vals.Add(b);
}
List<int> sievePrimes = simpleSieve(maxSquareRoot);
// simpleSieve is a standard SoE returning a list of primes not exceeding its argument
var sieve = new System.Collections.BitArray(max - min + 1);
int minSquareRoot = (int)Math.Sqrt(min);
foreach(int p in sievePrimes)
{
    int num = p > minSquareRoot ? p*p : ((min + p - 1)/p)*p;
    num -= min;
    for(; num <= max-min; num += p)
    {
        sieve[num] =true;
    }
}
List<int> primes = new List<int>();
for(int offset = 0; offset <= max-min; ++offset)
{
    if (!sieve[offset])
    {
        primes.Add(min + offset);
    }
}
lock(vals) vals.AddRange(primes);