Lyn
조회 수 32786 추천 수 0 댓글 4
Atachment
첨부 '1'
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄

C++의 STL 에서는 여러가지 알고리즘을 제공한다.
그중 "임의의" 동작을 할 수 있는 알고리즘들은 그 "동작" 의 대상이 되는 인자를 받도록 되어 있는데, 
그 "동작"의 조건은 ()연산자로 호출이 가능할것! 이다.


그 동작을 만족시키는것은 C에서는 함수가 있다.
또 C++에서는 STL 과 함께 소개된 함수객체(Functor)가 있으며, STL 초기부터 제공된 bind1st, bind2nd가 있고, boost에서 제공되는 mem_fn 도 있으며, 이 모든것을 통합한 범용 bind(C++11 or boost에 포함)도 존재한다.

그리고 최신의 C++11 표준에 포함된 lambda도 있고, boost의 lambda도 있지만, 이쪽은 C++11 표준에 lambda가 포함 된 이상 더이상 쓸 일은 없을테니 이번 실험에선 제외한다.


실험순서는 전역함수, bind된 전역함수, 함수객체, 람다, bind된 람다, auto를 이용해 bind된 람다 의 순이다.

실험은 Visual C++ 2010 Sp1, x86 Debug Build에서 테스트 하엿다. Release Mode 도 특성은 동일하다.

궂이 Debug Build로 테스트 한 이유는 Release모드에서 자꾸 전역함수를 inline화 시키는 바람에 =_=;


코드 나간다.


#include <cstdlib>
#include <cstdio>
#include <vector>
#include <random>
#include <cstdint>
#include <algorithm>
#include <functional>
#include <windows.h>
 
using namespace std;
 
__int64 g_NumberSum;
 
void GetSumFunction(int Num)
{
	g_NumberSum = g_NumberSum + Num;
}
 
struct GetSumFunctor
{
	void operator()(int Num)
	{
		g_NumberSum = g_NumberSum + Num;
	}
};
 
void wmain()
{
	const int NUMBER_COUNT = 100000000;
 
	mt19937_64 RandomEngine;
	uniform_int <> RandomRange(0, INT32_MAX);
	RandomEngine.seed(GetTickCount());
 
	vector<int> RandumNumbers;
	RandumNumbers.reserve(NUMBER_COUNT);
	for (int i = 0; i < NUMBER_COUNT; ++i)
	{
		RandumNumbers.push_back(RandomRange(RandomEngine));
	}
 
	DWORD Tick;
//function
	g_NumberSum = 0;
	Tick = GetTickCount();
	for_each(RandumNumbers.begin(), RandumNumbers.end(), GetSumFunction);
	printf("Global Function :: Sum : %I64d, Time : %dms\n", g_NumberSum, GetTickCount() - Tick);
//bind function
	g_NumberSum = 0;
	function<void(int)> FunctionObject = bind(&GetSumFunction, tr1::placeholders::_1);
	Tick = GetTickCount();
	for_each(RandumNumbers.begin(), RandumNumbers.end(), FunctionObject);
	printf("Bind Function   :: Sum : %I64d, Time : %dms\n", g_NumberSum, GetTickCount() - Tick);
//functor
	g_NumberSum = 0;
	Tick = GetTickCount();	
	for_each(RandumNumbers.begin(), RandumNumbers.end(), GetSumFunctor());
	printf("Functor         :: Sum : %I64d, Time : %dms\n", g_NumberSum, GetTickCount() - Tick);
//C++ 11 Lambda
	g_NumberSum = 0;
	Tick = GetTickCount();
	for_each(RandumNumbers.begin(), RandumNumbers.end(), 
		[](int Num)
		{
			g_NumberSum = g_NumberSum + Num;
		});
	printf("C++11 Lambda    :: Sum : %I64d, Time : %dms\n", g_NumberSum, GetTickCount() - Tick);
//C++11 Bind Lambda
	g_NumberSum = 0;
	Tick = GetTickCount();
	function<void(int)> BindLambda = 
		[](int Num)
		{
			g_NumberSum = g_NumberSum + Num;
		};
	for_each(RandumNumbers.begin(), RandumNumbers.end(), BindLambda);
	printf("Bind Lambda     :: Sum : %I64d, Time : %dms\n", g_NumberSum, GetTickCount() - Tick);
//C++11 Auto bind Lambda
	g_NumberSum = 0;
	Tick = GetTickCount();
	auto AutoBindLambda = 
		[](int Num)
		{
			g_NumberSum = g_NumberSum + Num;
		};
	for_each(RandumNumbers.begin(), RandumNumbers.end(), AutoBindLambda);
	printf("Auto Bind Lambda:: Sum : %I64d, Time : %dms\n", g_NumberSum, GetTickCount() - Tick); 
} 



아래는 결과이다.

lambda.png


결과를 보면 lambda 가 가장 빠른 것을 볼 수 있다. 길게 나불대지 않고 성능 이슈와 원인을 아래 간략히 적어본다.
1. 전역함수의 경우 함수 Call 오버헤드에 의해 속도가 조금 감소하엿다.

2. lambda, functor 는 사실상 오차범위 내의 차이라고 보인다.

3. bind lambda 의 경우는 std::fuction 객체가 함수호출 정보를 RTTI에 의존하는 특징때문에 속도를 왕창 까먹게 된다.

4. bind 된 전역함수의 경우는 RTTI의 오버헤드 + 함수호출로 인해 가장 느려진다.

5. auto를 사용해 변수에 저장한 lambda 는 std::fuction객체에 저장 하는 것이 아니라 일종의 inline 함수처럼 구현해준다. 그래서 오버헤드가 전혀 없이 빠른 속도를 보여준다. 즉 같은 함수객체를 2번이상 이용 할 경우 코드를 Copy&Paste 하지 않아도 auto를 이용하면 성능과 중복방지 두마리 코드를 다 잡을 수 있다.

?
  • ?
    elrha 2012.08.16 18:27

    으아 이거 좋은정보네요


    테스트는 안해봤지만 auto 객체 마우스 오버해보면 std::function으로 나올듯 한데..


    결국 컴파일러 지능테스트인건가요 ㅋㅋㅋㅋ

  • profile
    Lyn 2012.08.17 07:23

    아뇨 함수포인터 취급해요 ㅎㅎ


    컴파일 타임에 완전한 호출 정보를 알고있는 상황에서 궂이 오버헤드가 있는 std::function으로 컴파일할 이유가 없죠

  • ?
    11ho 2014.03.25 05:22
    감사합니다. 속이 다 후련하네요 ㅠㅠ
  • ?
    해피 2015.07.17 18:45
    퍼가용

List of Articles
번호 제목 글쓴이 날짜 조회 수
159 .net 4.7 의 WPF 가 DX11 기반으로 돌아가네요 Lyn 2017.06.23 1084
158 2014.10.14 일 Windows 업데이트 이후 VMWare Not enough physical memory available 오류 file Lyn 2014.10.16 19793
157 add "open as administrator" menu for gnome file explorer(nautilus) file Lyn 2016.06.25 4632
156 Android android.os.NetworkOnMainThreadException Lyn 2015.02.15 3414
155 Android Studio Gradle Error:Execution failed for task ':app:packageDebug'. > Duplicate files copied in 오류 해결 Lyn 2015.02.12 7338
154 asp.net core 3 에서 실행중에 cshtml 파일 변경이 되지 않는 이슈 Lyn 2019.12.17 283
153 Boost 빌드 방법 1 Lyn 2012.01.14 31876
152 Boost 에서 자기 자신의 shared_ptr 리턴하기 file Lyn 2010.03.02 38036
151 boost::icl::interval_map 원하는대로 변경해서 사용해보기 file Lyn 2013.09.23 22414
150 boost::interprocess::managed_shared_memory의 동작에 관하여 Lyn 2014.08.22 208862
149 boostpro 문 닫았네요.... file Lyn 2013.11.02 24056
148 C Runtime Library Exception Dump 남기기 두번째 방법 Lyn 2013.06.25 26021
147 C Runtime Library Exception Dump 남기기 첫번째방법 Lyn 2013.06.11 33235
146 C++ new 연산자의 진실 2 file Lyn 2009.08.19 58256
145 C++ string&형 인자에 기본값 주기 Lyn 2012.07.24 26082
144 C++ Template 의 inner class 로 type 선언 하기 Lyn 2014.10.29 23328
143 C++ 에서 Nuget 사용해 보기 file Lyn 2015.03.18 11320
142 C++ 에서 타 언어의 try-finally 흉내내기 1 file Lyn 2015.01.05 6889
141 C++ 템플릿 상속에서 베이스 클래스의 멤버에 접근하는 경우의 문제 1 file Lyn 2012.08.29 30661
» C++11 lambda 간단사용법과 성능비교. 4 file Lyn 2012.01.30 32786
Board Pagination Prev 1 2 3 4 5 6 7 ... 8 Next
/ 8