[위 에] C + + Pirate: Lambda vs Bind

16927 단어 lambda
Lambda 와 Bind 의 성능 비교
전재 출처 설명:http://blog.csdn.net/cywosp/article/details/9379403
먼저 아래 함 수 를 보 여 주세요.
 
template <typename Function>

void do_test_loop(Function func, const uint64_t upper_limit = 1000000000ULL)

{

    for (uint64_t i = 0; i < upper_limit; ++i)

        func(i);

}

 
            func   upper_limit(  10  )     。               func      ,          :
    1.   std::bind        std::function<void (uint64_t)>  。
    2.lambda   
void test_accumulate_bind_function(uint64_t& x, uint64_t i)

{

    x += i;

}



uint64_t test_accumulate_bind()

{

    namespace arg = std::placeholders;

    

    uint64_t x = 0;

    std::function<void (uint64_t)> accumulator = std::bind(&test_accumulate_bind_function, std::ref(x), arg::_1);

    do_test_loop(accumulator);

    return x;

}
          ,   boost::bind   ,                       ,            。         ,         ,                       (    ),          。
         lambda     :   
uint64_t test_accumulate_lambda()

{

    uint64_t x = 0;

    auto accumulator = [&x] (uint64_t i) { x += i; };

    do_test_loop(accumulator);

    return x;

}

 
 lambda              。  ,        std::function           。lambda                ,                 auto      。  accumulator  lambda      (     lambda             )。                       。  do_test_loop    cpp        ,                       lambda     。     ,                  ,     lambda        std::function         ,         :
uint64_t test_accumulate_bound_lambda()

{

    uint64_t x = 0;

    std::function<void (uint64_t)> accumulator = [&x] (uint64_t i) { x += i; };

    do_test_loop(accumulator);

    return x;

}
      lambda     std::bind,      std::function        C++ lambda               。          。
                   (  timer ):
template <typename Function>

void run_test(const std::string& name, Function func)

{

    std::cout << name;

    timer t;

    volatile_write(func());

    timer::duration duration = t.elapsed();

    std::cout << '\t' << duration.count() << std::endl;

}



int main()

{

    run_test("Accumulate (lambda)      ", &test_accumulate_lambda);

    run_test("Accumulate (bind)        ", &test_accumulate_bind);

    run_test("Accumulate (bound lambda)", &test_accumulate_bound_lambda);

}
    ,        gcc 4.4.2 -O3     Inter Core i7 Q740        :
Accumulate (lambda) 7 Accumulate (bind) 4401849 Accumulate (bound lambda) 4379315
(gdb) disassemble test_accumulate_lambda Dump of assembler code for function _Z22test_accumulate_lambdav: 0x0000000000400e70 <+0>: movabs $0x6f05b59b5e49b00,%rax 0x0000000000400e75 <+5>: retq End of assembler dump.
0x6f05b59b5e49b00(     :499999999500000000)    rax        。                 0 1000000000                       ,                         。      do_test_loop          ,                      :
uint64_t test_accumulate_lambda()

{

    uint64_t x = 0;

    // do_test_loop:

    for (uint64_t i = 0; i < 1000000000; ++i)

        x += i;

    return x;

}
                。                      :     lambda         ,          lambda          。       std::function          ?                ,   do_test_loop   std::function<void (uint64_t)>    ,       func   ,         (   std::function    )。std::bind lambda                。            ,      lambda       std::bind    ,                。                       ,           std::reference_wrapper   。               。
std::bind #0 test_accumulate_bind_function (x=@0x7fffffffe5d0, i=0) at lambda_vs_bind.cpp:106 #1 0x0000000000401111 in operator() (__args#0=0, this=<optimized out>) at /usr/local/include/gcc-4.6.2/functional:2161 #2 do_test_loop<std::function<void(long unsigned int)> > (func=<optimized out>, upper_limit=<optimized out>) at lambda_vs_bind.cpp:93 #3 test_accumulate_bind () at lambda_vs_bind.cpp:115 #4 0x0000000000401304 in run_test<unsigned long (*)()> (name=<optimized out>, func=0x401080 <test_accumulate_bind()>) at lambda_vs_bind.cpp:84 #5 0x0000000000401411 in main () at lambda_vs_bind.cpp:136
 Lambda Expression #0 std::_Function_handler<void(long unsigned int), test_accumulate_bound_lambda()::<lambda(uint64_t)> >::_M_invoke(const std::_Any_data &, unsigned long) (__functor=..., __args#0=0) at /usr/local/include/gcc-4.6.2/functional:1778 #1 0x0000000000400fa9 in operator() (__args#0=0, this=<optimized out> at /usr/local/include/gcc-4.6.2/functional:2161 #2 do_test_loop<std::function<void(long unsigned int)> > (func=<optimized out>, upper_limit=<optimized out>) at lambda_vs_bind.cpp:93 #3 test_accumulate_bound_lambda () at lambda_vs_bind.cpp:126 #4 0x0000000000401304 in run_test<unsigned long (*)()> (name=<optimized out>, func=0x400f20 <test_accumulate_bound_lambda()>) at lambda_vs_bind.cpp:84 #5 0x000000000040143e in main () at lambda_vs_bind.cpp:140
           std::function operator()    ,         ,         g++ 4.6.2 std::function      :
template<typename _Res, typename... _ArgTypes>

class function<_Res(_ArgTypes...)>

    : public _Maybe_unary_or_binary_function<_Res, _ArgTypes...>,

      private _Function_base

{

    // a whole bunch of implementation details



private:

    typedef _Res (*_Invoker_type)(const _Any_data&, _ArgTypes...);

    _Invoker_type _M_invoker;

};
        std::function    virtual           。          ,         std::function           ——            。
boost:bind
     boost::bind      ?      ,              boost   std。
Accumulate (boost bind) 3223174 Accumulate (boost bound lambda) 4255098
        boost::bind  std::bind  25%  ,boost::bind      std::bind       :
#0 test_accumulate_bind_function (x=@0x7fffffffe600, i=0) at lambda_vs_bind.cpp:114 #1 0x00000000004018a3 in operator() (a0=0, this=<optimized out>) at /usr/local/include/boost/function/function_template.hpp:1013 #2 do_test_loop<boost::function<void(long unsigned int)> > (upper_limit=<optimized out>, func=<optimized out>) at lambda_vs_bind.cpp:101 #3 test_accumulate_boost_bind () at lambda_vs_bind.cpp:144 #4 0x0000000000401f44 in run_test<unsigned long (*)()> (name=<optimized out>, func=0x401800 <test_accumulate_boost_bind()>) at lambda_vs_bind.cpp:92 #5 0x000000000040207e in main () at lambda_vs_bind.cpp:161
(                  boost::bind  std::bind  ... ...)
functional

template<typename _Functor, typename... _ArgTypes>

inline

typename _Bind_helper<_Functor, _ArgTypes...>::type

bind(_Functor&& __f, _ArgTypes&&... __args)

{

    typedef _Bind_helper<_Functor, _ArgTypes...> __helper_type;

    typedef typename __helper_type::__maybe_type __maybe_type;

    typedef typename __helper_type::type __result_type;

    return __result_type(__maybe_type::__do_wrap(std::forward<_Functor>(__f)),

                        std::forward<_ArgTypes>(__args)...);

}

boost/bind/bind.hpp (with the macros expanded)

template<class F, class A1, class A2>

    _bi::bind_t<_bi::unspecified, F, typename _bi::list_av_2<A1, A2>::type>

    bind(F f, A1 a1, A2 a2)

{

    typedef typename _bi::list_av_2<A1, A2>::type list_type;

    return _bi::bind_t<_bi::unspecified, F, list_type> (f, list_type(a1, a2));

}
    
1.    
                http://www.gockelhut.com/c++/files/lambda_vs_bind.cpp。  g++ 4.6.2                ,   c++11             。  Boost     1.47,                    ,  boost::bind               (     )。             boost,   USE_BOOST    0  。
2. volatile_write

volatile_write 함 수 는 시스템 이 메모리 에 데 이 터 를 쓰 도록 강제 하 는 간단 한 함수 입 니 다. 그러면 최적화 기 가 함수 run 을 최적화 하 는 것 을 방지 할 수 있 습 니 다.test 에는 아무것도 할 코드 가 없습니다.
template <typename T>

void volatile_write(const T& x)

{

    volatile T* p = new T;

    *p = x;

    delete p;

}
    :http://www.gockelhut.com/c++/articles/lambda_vs_bind
lambda_vs_bind.cpp
/**

 *   Copyright 2011 Travis Gockel

 *

 *  Licensed under the Apache License, Version 2.0 (the "License");

 *  you may not use this file except in compliance with the License.

 *  You may obtain a copy of the License at

 *

 *      http://www.apache.org/licenses/LICENSE-2.0

 *

 *  Unless required by applicable law or agreed to in writing, software

 *  distributed under the License is distributed on an "AS IS" BASIS,

 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 *  See the License for the specific language governing permissions and

 *  limitations under the License.

**/



// Turn building and testing boost::bind on or off with this macro

#define USE_BOOST 1



// workaround for varieties of g++-4.6 with --std=gnu++0x

#ifndef _GLIBCXX_USE_NANOSLEEP

#   define _GLIBCXX_USE_NANOSLEEP

#endif



#include <cstdint>

#include <chrono>

#include <iostream>

#include <string>

#include <thread>



#if USE_BOOST

#include <boost/function.hpp>

#include <boost/bind.hpp>

#endif



class timer

{

public:

    typedef std::chrono::high_resolution_clock clock;

    typedef clock::time_point                  time_point;

    typedef clock::duration                    duration;

    

public:

    timer()

    {

        reset();

    }

    

    void reset()

    {

        _starttime = clock::now();

    }



    duration elapsed() const

    {

        return clock::now() - _starttime;

    }

protected:

    time_point _starttime;

};



bool test_timer()

{

    using std::chrono::milliseconds;

    typedef timer::duration duration;

    

    const milliseconds sleep_time(500);

    

    timer t;

    std::this_thread::sleep_for(sleep_time);

    duration recorded = t.elapsed();

    

    // make sure the clock and this_thread::sleep_for is precise within one millisecond (or at least in agreement as to

    // how inaccurate they are)

    return (recorded - milliseconds(1) < sleep_time)

        && (recorded + milliseconds(1) > sleep_time);

}



template <typename T>

void volatile_write(const T& x)

{

    volatile T* p = new T;

    *p = x;

    delete p;

}



template <typename Function>

void run_test(const std::string& name, Function func)

{

    std::cout << name;

    timer t;

    volatile_write(func());

    timer::duration duration = t.elapsed();

    std::cout << '\t' << duration.count() << std::endl;

}



template <typename Function>

void do_test_loop(Function func, const uint64_t upper_limit = 1000000000ULL)

{

    for (uint64_t i = 0; i < upper_limit; ++i)

        func(i);

}



uint64_t test_accumulate_lambda()

{

    uint64_t x = 0;

    auto accumulator = [&x] (uint64_t i) { x += i; };

    do_test_loop(accumulator);

    return x;

}



void test_accumulate_bind_function(uint64_t& x, uint64_t i)

{

    x += i;

}



uint64_t test_accumulate_bind()

{

    namespace arg = std::placeholders;

    

    uint64_t x = 0;

    std::function<void (uint64_t)> accumulator = std::bind(&test_accumulate_bind_function, std::ref(x), arg::_1);

    do_test_loop(accumulator);

    return x;

}



uint64_t test_accumulate_bound_lambda()

{

    uint64_t x = 0;

    std::function<void (uint64_t)> accumulator = [&x] (uint64_t i) { x += i; };

    do_test_loop(accumulator);

    return x;

}



#if USE_BOOST

uint64_t test_accumulate_boost_bind()

{

    uint64_t x = 0;

    

    boost::function<void (uint64_t)> accumulator = boost::bind(&test_accumulate_bind_function, boost::ref(x), _1);

    do_test_loop(accumulator);

    return x;

}



uint64_t test_accumulate_boost_bound_lambda()

{

    uint64_t x = 0;

    boost::function<void (uint64_t)> accumulator = [&x] (uint64_t i) { x += i; };

    do_test_loop(accumulator);

    return x;

}

#endif



int main()

{

    if (!test_timer())

    {

        std::cout << "Failed timer test." << std::endl;

        return -1;

    }

    

    run_test("Accumulate (lambda)            ", &test_accumulate_lambda);

    run_test("Accumulate (bind)              ", &test_accumulate_bind);

    run_test("Accumulate (bound lambda)      ", &test_accumulate_bound_lambda);

    #if USE_BOOST

    run_test("Accumulate (boost bind)        ", &test_accumulate_boost_bind);

    run_test("Accumulate (boost bound lambda)", &test_accumulate_bound_lambda);

    #endif

}

좋은 웹페이지 즐겨찾기