C# 生成素数序列,循环中断vs LINQ TakeWhile

C# 生成素数序列,循环中断vs LINQ TakeWhile,c#,linq,primes,C#,Linq,Primes,我尝试用C#生成素数序列。 到目前为止,代码似乎运行良好 List<int> _primes = new List<int>(); bool IsPrime(int num) { if (num < 2) return false; int chkEnd = (int)Math.Sqrt(num); foreach (var p in _primes) { if (p > chkEnd)

我尝试用C#生成素数序列。 到目前为止,代码似乎运行良好

List<int> _primes = new List<int>();

bool IsPrime(int num)
{
    if (num < 2)
        return false;
    int chkEnd = (int)Math.Sqrt(num);

    foreach (var p in _primes)
    {
        if (p > chkEnd)
            break;
        if (num % p == 0)
            return false;
    }
    return true;
}

for (int i=2; i<1000000; i++)
{
    if (IsPrime(i))
        _primes.Add(i);
}
List_primes=newlist();
bool IsPrime(整数)
{
if(num<2)
返回false;
int chkEnd=(int)Math.Sqrt(num);
foreach(var p in_素数)
{
如果(p>chkEnd)
打破
如果(num%p==0)
返回false;
}
返回true;
}
对于(int i=2;i x num%p!=0);
}
有人知道吗


编辑: 我将循环迭代次数增加到5000000,在控制台应用程序中运行代码并输出执行时间

00:00:01.1841593——iPrime_PureLoopBreak

00:00:03.2560654——iPrime_TakeWhileAndLoop

00:00:03.4178782——IsPrime_takewhilendall

    static void Main(string[] args)
    {
        List<int> _primes;

        bool IsPrime_PureLoopBreak(int num)
        {
            if (num < 2)
                return false;
            int chkEnd = (int)Math.Sqrt(num);

            foreach (var p in _primes)
            {
                if (p > chkEnd)
                    break;
                if (num % p == 0)
                    return false;
            }
            return true;
        }

        bool IsPrime_TakeWhileAndLoop(int num)
        {
            if (num < 2)
                return false;
            int chkEnd = (int)Math.Sqrt(num);

            foreach (var p in _primes.TakeWhile(x => x <= chkEnd))
            {
                if (num % p == 0)
                    return false;
            }
            return true;
        }

        bool IsPrime_TakeWhileAndAll(int num)
        {
            if (num < 2)
                return false;
            int chkEnd = (int)Math.Sqrt(num);

            return _primes.TakeWhile(x => x <= chkEnd).All(p => num % p != 0);
        }

        var t1 = Measure(() => 
        {
            _primes = new List<int>();
            for (int i = 2; i < 5000000; i++)
            {
                if (IsPrime_PureLoopBreak(i))
                    _primes.Add(i);
            }
        });
        Console.WriteLine($"{t1} -- IsPrime_PureLoopBreak");

        var t2 = Measure(() =>
        {
            _primes = new List<int>();
            for (int i = 2; i < 5000000; i++)
            {
                if (IsPrime_TakeWhileAndLoop(i))
                    _primes.Add(i);
            }
        });
        Console.WriteLine($"{t2} -- IsPrime_TakeWhileAndLoop");

        var t3 = Measure(() =>
        {
            _primes = new List<int>();
            for (int i = 2; i < 5000000; i++)
            {
                if (IsPrime_TakeWhileAndAll(i))
                    _primes.Add(i);
            }
        });
        Console.WriteLine($"{t3} -- IsPrime_TakeWhileAndAll");

        Console.ReadLine();
    }

    public static TimeSpan Measure(Action action)
    {
        var stopwatch = new Stopwatch();
        stopwatch.Start();
        action?.Invoke();
        stopwatch.Stop();
        return stopwatch.Elapsed;
    }
static void Main(字符串[]args)
{
列出素数;
bool IsPrime_PureLoopBreak(整数)
{
if(num<2)
返回false;
int chkEnd=(int)Math.Sqrt(num);
foreach(var p in_素数)
{
如果(p>chkEnd)
打破
如果(num%p==0)
返回false;
}
返回true;
}
bool IsPrime_TakeWhileAndLoop(整数)
{
if(num<2)
返回false;
int chkEnd=(int)Math.Sqrt(num);
foreach(var p在_primes.TakeWhile中(x=>x num%p!=0);
}
变量t1=度量(()=>
{
_素数=新列表();
对于(int i=2;i<5000000;i++)
{
if(iPrime_PureLoopBreak(i))
_加上(i);
}
});
WriteLine($“{t1}--IsPrime_PureLoopBreak”);
变量t2=度量(()=>
{
_素数=新列表();
对于(int i=2;i<5000000;i++)
{
if(i优先权)
_加上(i);
}
});
Console.WriteLine($“{t2}--IsPrime_TakeWhileAndLoop”);
变量t3=度量(()=>
{
_素数=新列表();
对于(int i=2;i<5000000;i++)
{
if(i优先权(i))
_加上(i);
}
});
Console.WriteLine($“{t3}--IsPrime_takewhilendall”);
Console.ReadLine();
}
公共静态时间跨度度量(操作)
{
var stopwatch=新秒表();
秒表。开始();
action?.Invoke();
秒表;
返回秒表。已过;
}

使用LINQ有一些额外的开销。您正在创建和调用lambda表达式


但是,在得出结论之前,一定要尝试发布版本。

考虑编译器需要生成的代码。“高级”代码(如Linq)简单易写,但编译器通常更难很好地优化

您前面的示例可以进一步简化为使用普通for循环而不是foreach,因此每次迭代只需要少量指令

使用linq时,编译器将为迭代器生成一个代理对象。这需要调用lambda以检查是否需要继续迭代,并且编译器可能无法内联方法调用。方法调用很便宜,但仍然比简单的算术指令贵几倍


因此,根据经验,使用Linq和其他高级模式来提高可读性。如果您发现代码中的某些部分没有达到性能目标,请使用探查器准确地确定哪些部分需要时间,然后重写该部分,直到速度足够快或尽可能快。

您有什么问题?“执行时间显著增加”
bool IsPrime(int num)
{
    if (num < 2)
        return false;
    int chkEnd = (int)Math.Sqrt(num);

    return _primes.TakeWhile(x => x <= chkEnd).All(p => num % p != 0);
}
    static void Main(string[] args)
    {
        List<int> _primes;

        bool IsPrime_PureLoopBreak(int num)
        {
            if (num < 2)
                return false;
            int chkEnd = (int)Math.Sqrt(num);

            foreach (var p in _primes)
            {
                if (p > chkEnd)
                    break;
                if (num % p == 0)
                    return false;
            }
            return true;
        }

        bool IsPrime_TakeWhileAndLoop(int num)
        {
            if (num < 2)
                return false;
            int chkEnd = (int)Math.Sqrt(num);

            foreach (var p in _primes.TakeWhile(x => x <= chkEnd))
            {
                if (num % p == 0)
                    return false;
            }
            return true;
        }

        bool IsPrime_TakeWhileAndAll(int num)
        {
            if (num < 2)
                return false;
            int chkEnd = (int)Math.Sqrt(num);

            return _primes.TakeWhile(x => x <= chkEnd).All(p => num % p != 0);
        }

        var t1 = Measure(() => 
        {
            _primes = new List<int>();
            for (int i = 2; i < 5000000; i++)
            {
                if (IsPrime_PureLoopBreak(i))
                    _primes.Add(i);
            }
        });
        Console.WriteLine($"{t1} -- IsPrime_PureLoopBreak");

        var t2 = Measure(() =>
        {
            _primes = new List<int>();
            for (int i = 2; i < 5000000; i++)
            {
                if (IsPrime_TakeWhileAndLoop(i))
                    _primes.Add(i);
            }
        });
        Console.WriteLine($"{t2} -- IsPrime_TakeWhileAndLoop");

        var t3 = Measure(() =>
        {
            _primes = new List<int>();
            for (int i = 2; i < 5000000; i++)
            {
                if (IsPrime_TakeWhileAndAll(i))
                    _primes.Add(i);
            }
        });
        Console.WriteLine($"{t3} -- IsPrime_TakeWhileAndAll");

        Console.ReadLine();
    }

    public static TimeSpan Measure(Action action)
    {
        var stopwatch = new Stopwatch();
        stopwatch.Start();
        action?.Invoke();
        stopwatch.Stop();
        return stopwatch.Elapsed;
    }