首页 > 解决方案 > 如何提高 C# 中的 foreach 循环性能

问题描述

class Student
{
    public int ID { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
}

class Program
{
    private static object _lockObj = new object();

    static void Main(string[] args)
    {

        List<int> collection = Enumerable.Range(1, 100000).ToList();


         
        List<Student> students = new List<Student>(100000);
        var options = new ParallelOptions()
        {
            MaxDegreeOfParallelism = 1
        };
        var sp = System.Diagnostics.Stopwatch.StartNew();
        sp.Start();
        Parallel.ForEach(collection, options, action =>
        {
            lock (_lockObj)
            {
                 var dt = collection.FirstOrDefault(x => x == action);
                 if (dt > 0)
                 {
                    Student student = new Student();
                    student.ID = dt;
                    student.Name = "Zoyeb";
                    student.Email = "ShaikhZoyeb@Gmail.com";

                    students.Add(student);
                    Console.WriteLine(@"value of i = {0}, thread = {1}", 
                    action,Thread.CurrentThread.ManagedThreadId);
                }
            }
        });
        sp.Stop();

        double data = Convert.ToDouble(sp.ElapsedMilliseconds / 1000);
        Console.WriteLine(data);
         
    }
}

我想尽快循环遍历 100000 条记录我尝试了 foreach 循环,但是对于循环遍历 100000 条记录并不是很好,然后在我尝试实现 Parallel.ForEach() 提高了我的性能之后,在实际场景中我将收集Ids 和我需要查找集合是否 id 退出,如果退出然后添加。当我评论条件大约需要 3 秒来执行,而当我取消注释条件大约需要 24 秒,所以我的问题是有什么方法可以通过在集合中查找 id 来提高我的性能

         //var dt = collection.FirstOrDefault(x => x == action);
         //if (dt > 0)
         //{
            Student student = new Student();
            student.ID = 1;
            student.Name = "Zoyeb";
            student.Email = "ShaikhZoyeb@Gmail.com";

            students.Add(student);
            Console.WriteLine(@"value of i = {0}, thread = {1}", 
            action,Thread.CurrentThread.ManagedThreadId);
        //}

标签: c#

解决方案


您的原始代码正在执行 a lockinside a Parallel.ForEach。这本质上是采用并行代码并强制它串行运行。

在我的机器上需要 40 秒。

这实际上相当于这样做:

    foreach (var action in collection)
    {
            var dt = collection.FirstOrDefault(x => x == action);
            if (dt > 0)
            {
                Student student = new Student();
                student.ID = dt;
                student.Name = "Zoyeb";
                student.Email = "ShaikhZoyeb@Gmail.com";

                students.Add(student);
            }
    }

这也需要40秒。

但是,如果你这样做:

    foreach (var action in collection)
    {
        Student student = new Student();
        student.ID = action;
        student.Name = "Zoyeb";
        student.Email = "ShaikhZoyeb@Gmail.com";

        students.Add(student);
    }

运行需要 1毫秒。它大约快 40,000 倍。

在这种情况下,您可以通过一次迭代您的集合来获得更快的循环,而不是以嵌套方式并且不使用Parallel.ForEach.


我很抱歉错过了关于 id 不存在的信息。

尝试这个:

    HashSet<int> hashSet = new HashSet<int>(collection);

    List<Student> students = new List<Student>(100000);

    var sp = System.Diagnostics.Stopwatch.StartNew();
    sp.Start();
    foreach (var action in collection)
    {
        if (hashSet.Contains(action))
        {
            Student student = new Student();
            student.ID = action;
            student.Name = "Zoyeb";
            student.Email = "ShaikhZoyeb@Gmail.com";

            students.Add(student);
        }
    }
    sp.Stop();

运行时间为 3 毫秒。

另一种方法是使用join这样的:

    foreach (var action in
        from c in collection
        join dt in collection on c equals dt
        select dt)
    {
        Student student = new Student();
        student.ID = action;
        student.Name = "Zoyeb";
        student.Email = "ShaikhZoyeb@Gmail.com";

        students.Add(student);
    }

运行时间为 25 毫秒。


推荐阅读