C# 속도 비교: Tuple vs KeyValuePair 4가지 방법 사용


Tuple vs KeyValuePair. 두 항목의 성능(속도와 처리 성능)에 대한 간단한 비교 예제입니다. 이 글을 통해 ui 속도 개선에 도움이 되길 바랍니다.


8.23 ns -- Allocate Tuple

0.32 ns -- Allocate KeyValuePair


1.93 ns -- Pass Tuple as argument

2.57 ns -- Pass KeyValuePair as argument


1.91 ns -- Return Tuple

6.09 ns -- Return KeyValuePair


2.79 ns -- Load Tuple from List

4.18 ns -- Load KeyValuePair from List


4가지 방법으로 간단히 살펴본 결과이며, 기준은 처리 속도 비교입니다. 수행 시간은 나노초입니다.

아래는 4가지 방법입니다.

  • Allocation : 이 테스트는 인스턴스 생성을 반복합니다. new 키워드가 사용됩니다.
  • Argument : 각 인스턴스는 다른 (non-inline) 함수로 전달됩니다.
  • Return : 각 인스턴스는 다른 함수로 전달된 후 반환됩니다.
  • Load : 각 인스턴스는 다른 함수로 전달되어 List 컬렉션에 저장된 후 반환됩니다.


예제 소스 다운로드


Tuple vs KeyValuePair.txt


using System;

using System.Collections.Generic;

using System.Diagnostics;

using System.Runtime.CompilerServices;

 

class Program

{

    static void Main()

    {

    Allocation();

    Argument();

    Return();

    Load();

    Console.Read();

    }

 

    static void Allocation()

    {

    const int max = 1000000;

    var a = new Tuple<string, string>("", "");

    var b = new KeyValuePair<string, string>("", "");

 

    var s1 = Stopwatch.StartNew();

    for (int i = 0; i < max; i++)

    {

        var tuple = new Tuple<string, string>("cat", "dog");

    }

    s1.Stop();

    var s2 = Stopwatch.StartNew();

    for (int i = 0; i < max; i++)

    {

        var pair = new KeyValuePair<string, string>("cat", "dog");

    }

    s2.Stop();

    Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000000) /

        max).ToString("0.00 ns"));

    Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000000) /

        max).ToString("0.00 ns"));

    Console.WriteLine();

    }

 

    static void Argument()

    {

    const int max = 10000000;

    var a = new Tuple<string, string>("", "");

    var b = new KeyValuePair<string, string>("", "");

    X(a);

    X(b);

 

    var s1 = Stopwatch.StartNew();

    for (int i = 0; i < max; i++)

    {

        X(a);

    }

    s1.Stop();

    var s2 = Stopwatch.StartNew();

    for (int i = 0; i < max; i++)

    {

        X(b);

    }

    s2.Stop();

    Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000000) /

        max).ToString("0.00 ns"));

    Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000000) /

        max).ToString("0.00 ns"));

    Console.WriteLine();

    }

 

    static void Return()

    {

    const int max = 10000000;

    var a = new Tuple<string, string>("", "");

    var b = new KeyValuePair<string, string>("", "");

    Y(a);

    Y(b);

 

    var s1 = Stopwatch.StartNew();

    for (int i = 0; i < max; i++)

    {

        Y(a);

    }

    s1.Stop();

    var s2 = Stopwatch.StartNew();

    for (int i = 0; i < max; i++)

    {

        Y(b);

    }

    s2.Stop();

    Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000000) /

        max).ToString("0.00 ns"));

    Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000000) /

        max).ToString("0.00 ns"));

    Console.WriteLine();

    }

 

    static void Load()

    {

    const int max = 10000000;

    var a = new Tuple<string, string>("cat", "dog");

    var b = new KeyValuePair<string, string>("cat", "dog");

    List<Tuple<string, string>> list1 = new List<Tuple<string, string>>();

    list1.Add(a);

    Z(list1);

 

    List<KeyValuePair<string, string>> list2 = new List<KeyValuePair<string, string>>();

    list2.Add(b);

    Z(list2);

 

    var s1 = Stopwatch.StartNew();

    for (int i = 0; i < max; i++)

    {

        Z(list1);

    }

    s1.Stop();

    var s2 = Stopwatch.StartNew();

    for (int i = 0; i < max; i++)

    {

        Z(list2);

    }

    s2.Stop();

    Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000000) /

        max).ToString("0.00 ns"));

    Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000000) /

        max).ToString("0.00 ns"));

    Console.WriteLine();

    }

 

    [MethodImpl(MethodImplOptions.NoInlining)]

    static void X(Tuple<string, string> a)

    {

    }

 

    [MethodImpl(MethodImplOptions.NoInlining)]

    static void X(KeyValuePair<string, string> a)

    {

    }

 

    [MethodImpl(MethodImplOptions.NoInlining)]

    static Tuple<string, string> Y(Tuple<string, string> a)

    {

    return a;

    }

 

    [MethodImpl(MethodImplOptions.NoInlining)]

    static KeyValuePair<string, string> Y(KeyValuePair<string, string> a)

    {

    return a;

    }

 

    static char Z(List<Tuple<string, string>> list)

    {

    return list[0].Item1[0];

    }

 

    static char Z(List<KeyValuePair<string, string>> list)

    {

    return list[0].Key[0];

    }

}



return list[0].Key[0];



속도 비교 결과

 

8.23 ns

0.32 ns

 

1.93 ns

2.57 ns

 

1.91 ns

6.09 ns

 

2.79 ns

4.18 ns

Discussion. 튜플은 할당 성능을 빼곤 KeyValuePair 보다 모든 면에서 빨랐습니다. 따라서, 할당 이외의 작업이 더 많다면 Tuple을 사용하는 것이 더 좋습니다.


Using structs. 구조체를 사용하는 방법은 좋지 않습니다. 구조체는 모두 데이터 유형이라 모든 호출 과정에서 복사되어 전달하기 때문입니다.


Summary. 할당 동작은 KeyValuePair가 빨랐으나 나머지에선 Tuple이 더 빨랐습니다. 이렇듯 성능 상의 차이가 있으니 KeyValuePair는 지양하고 Tuple 사용을 지향해야 합니다. ui 속도 개선에 밀접한 관련이 있습니다.


C# 관련 글


댓글(2)

Designed by JB FACTORY