본문 바로가기

프로그래밍/C#, WPF, Winform

C# Find vs FirstOrDefault vs Where + FirstOrDefault vs for loop





대용량 자료구조를 검색할 일이 생기다보면

 

종종사용하게되는 함수가 Find, FirstOrDefault 인데..

 

이것이들 내부적으로는 다르게 돌아가서 속도 차이가 난다고한다.

 

 

실제로 얼마나 차이가 나는지 간단한 코드로 테스트해보았다.

 

테스트 환경

CPU : Intel i5-9600K 3.7GHz
운영체제 : 윈도우 10 64비트
컴파일러 : Visual Studio 2019 Community
검색 개수 : 30,000,000 (3천만개)
검색 조건 : 제일 마지막 데이터 검색

 

첫번째 케이스 : Find 10회 결과(ms)

RunTime1 : 438 ms
RunTime1 : 438 ms
RunTime1 : 424 ms
RunTime1 : 434 ms
RunTime1 : 427 ms
RunTime1 : 431 ms
RunTime1 : 424 ms
RunTime1 : 425 ms
RunTime1 : 431 ms
RunTime1 : 432 ms
RunTime1 Average : 430.4 ms

두번째케이스 : FirstOrDefault 10회 결과(ms)

RunTime2 : 625 ms
RunTime2 : 583 ms
RunTime2 : 578 ms
RunTime2 : 579 ms
RunTime2 : 580 ms
RunTime2 : 581 ms
RunTime2 : 581 ms
RunTime2 : 587 ms
RunTime2 : 579 ms
RunTime2 : 583 ms
RunTime2 Average : 585.6 ms

세번째케이스 : Where + FirstOrDefault 10회 결과(ms)

RunTime3 : 525 ms
RunTime3 : 516 ms
RunTime3 : 514 ms
RunTime3 : 508 ms
RunTime3 : 530 ms
RunTime3 : 515 ms
RunTime3 : 512 ms
RunTime3 : 512 ms
RunTime3 : 521 ms
RunTime3 : 516 ms
RunTime3 Average : 516.9 ms

네번째케이스 : for loop 10회 결과(ms)

RunTime4 : 424 ms
RunTime4 : 403 ms
RunTime4 : 407 ms
RunTime4 : 406 ms
RunTime4 : 402 ms
RunTime4 : 405 ms
RunTime4 : 411 ms
RunTime4 : 403 ms
RunTime4 : 411 ms
RunTime4 : 410 ms
RunTime4 Average : 408.2 ms

 

결과 

for loop(408.2 ms) > Find(430.4 ms) > Where + FirstOrDefault(516.9 ms) > FirstOrDefault(585.6 ms

 

테스트 코드

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
namespace ListSearchSpeedTest
{
    public partial class Form1 : Form
    {
        List<UserData> listUserData = new List<UserData>();
        public Form1()
        {
            InitializeComponent();
        }
 
        private void Form1_Load(object sender, EventArgs e)
        {
            for (int i = 0; i <= 30000000; i++)
            {
                listUserData.Add(
                    new UserData
                    {
                        ID = i.ToString(),
                        Name = i + "th Junior"
                    }
                    );
            }
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            List<long> listResult = new List<long>();
            Stopwatch stopWatch = new Stopwatch();
            for (int i = 0; i < 10; i++)
            {
                stopWatch.Restart();
 
                UserData item = listUserData.Find(x => x.ID == "30000000");
 
                stopWatch.Stop();
                listResult.Add(stopWatch.ElapsedMilliseconds);
                Console.WriteLine("RunTime1 : " + stopWatch.ElapsedMilliseconds + " ms");
            }
 
            Console.WriteLine("RunTime1 Average : " + listResult.Average() + " ms");
        }
 
        private void button2_Click(object sender, EventArgs e)
        {
            List<long> listResult = new List<long>();
            Stopwatch stopWatch = new Stopwatch();
            for (int i = 0; i < 10; i++)
            {
                stopWatch.Restart();
 
                UserData item = listUserData.FirstOrDefault(x => x.ID == "30000000");
 
                stopWatch.Stop();
                listResult.Add(stopWatch.ElapsedMilliseconds);
                Console.WriteLine("RunTime2 : " + stopWatch.ElapsedMilliseconds + " ms");
            }
 
            Console.WriteLine("RunTime2 Average : " + listResult.Average() + " ms");
        }
 
        private void button3_Click(object sender, EventArgs e)
        {
            List<long> listResult = new List<long>();
            Stopwatch stopWatch = new Stopwatch();
            for (int i = 0; i < 10; i++)
            {
                stopWatch.Restart();
 
                UserData item = listUserData.Where(x => x.ID == "30000000").FirstOrDefault();
 
                stopWatch.Stop();
                listResult.Add(stopWatch.ElapsedMilliseconds);
                Console.WriteLine("RunTime3 : " + stopWatch.ElapsedMilliseconds + " ms");
            }
 
            Console.WriteLine("RunTime3 Average : " + listResult.Average() + " ms");
        }
 
        private void button4_Click(object sender, EventArgs e)
        {
            List<long> listResult = new List<long>();
            Stopwatch stopWatch = new Stopwatch();
            for (int i = 0; i < 10; i++)
            {
                stopWatch.Restart();
 
                for (int j = 0; j <= 30000000; j++)
                {
                    if (listUserData[j].ID == "30000000")
                        break;
                }
 
                stopWatch.Stop();
                listResult.Add(stopWatch.ElapsedMilliseconds);
                Console.WriteLine("RunTime4 : " + stopWatch.ElapsedMilliseconds + " ms");
            }
 
            Console.WriteLine("RunTime4 Average : " + listResult.Average() + " ms");
 
        }
    }
 
    public class UserData
    { 
        public string ID { get; set; }
        public string Name { get; set; }
    }
 
}
 
cs