Welcome to Parallel C#(13) - 더 편하겡... 더 빠르겡...

C# Parallel Programming 2012. 2. 10. 09:00 Posted by 알 수 없는 사용자

- 뭐 좀 더 편한 방법이?

지난 포스팅에서는 Monitor를 좀 더 간편하게 사용할 수 있게 해주는 lock구문에 대해서 살펴봤었습니다. 그런데... 더 편한 방법이 있다는 군요. 한 줄이면 된다고 합니다. 긴 말 필요없이 예제를 보죠!

using System;

using System.Threading.Tasks;

using System.Threading;

 

namespace Exam25

{

    class Program

    {

        static readonly int count = 10000000;

        static int sum = 0;

 

        static void IncreaseByOne()

        {

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

            {

                Interlocked.Increment(ref sum);

            }

        }

 

        static void Main(string[] args)

        {

            Task task = Task.Factory.StartNew(IncreaseByOne);

 

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

            {

                Interlocked.Decrement(ref sum);

            }

 

            task.Wait();

            Console.WriteLine("Result = {0}", sum);

        }

    }

}

위 예제는 정확하게 lock을 사용한 예제와 동일한 결과를 냅니다. Interlocked라는 클래스에 정의된 메서드를 통해서 1씩 증가시키고 감소를 시킨거죠. 즉, lock사용해서 명시적으로 락을 획득하는 대신에 스레드 안전한 방식으로 값을 증가시키고 감소시키도록 하는 것입니다. 그런데, 여기까지만 보면 약간의 의문이 생깁니다. 생각보다 더 간단해 보이지가 않는 다는 말이죠. 허허허허 :)

그런데 한 가지 장점이 더 있습니다. 바로 수행 속도 인데요. 잠금을 획득하고 해제하는 게 시간이 많이 걸리는 작업이다 보니, lock을 사용하는 것보다 Interlocked를 사용하는 게 조금 더 빠릅니다. 그럼 얼마나 더 빠르다는 건지 간단한 코드를 통해서 직접 확인을 해볼까욤?

using System;
using System.Threading.Tasks;
using System.Threading;

namespace Exam26
{
    class Program
    {
        readonly static object sync = new object();
        static readonly int count = 10000000;
        static int sum = 0;       

        static void SpeedTest()
        {
            DateTime lockStart = DateTime.Now;
            for (int i = 0; i < count; i++)
            {
                lock (sync)
                {
                    sum++;
                }
            }
            DateTime lockEnd = DateTime.Now;
            TimeSpan lockResult = lockEnd - lockStart;

            sum = 0;

            DateTime InterlockedStart = DateTime.Now;

            for (int i = 0; i < count; i++)
            {
                Interlocked.Increment(ref sum);
            }
            DateTime InterlockedEnd = DateTime.Now;
            TimeSpan InterlockedResult = InterlockedEnd - InterlockedStart;

            Console.WriteLine("lock Result : {0}", lockResult);
            Console.WriteLine("Interlocked Result : {0}", InterlockedResult);
        }

        static void Main(string[] args)
        {
            //JIT 컴파일 수행
            SpeedTest();

            SpeedTest();
        }
    }
}


수행된 결과를 볼까요?

lock Result : 00:00:00.3270844
Interlocked Result : 00:00:00.1820249
lock Result : 00:00:00.3090990
Interlocked Result : 00:00:00.1820285
Press any key to continue . . .

두 번째 실행된 결과를 보면 Interlocked를 사용한 쪽이 70%정도 더 빠른 속도를 보이는 것을 할 수 있습니다. 위 코드 같이 단순한 연산이 많이 수행되는 경우에는 Interlocked를 사용하는 쪽이 조금 더 유리할 수 있겠죠. 물론 요즘 세상에 별로 신경쓸만한 차이는 아니라고 생각이 듭니다. 하하하하 그냥 이런 것도 있다는 거죠 :)

그럼, 오늘도 이만 하구요~ 다음에 또 뵙죵 하하하 :)