Re[6]: BOOST, .NET, String.Split и производительность…
От: Denis2005 Россия  
Дата: 20.09.06 08:24
Оценка: :)
Здравствуйте, VladD2, Вы писали:

Цель то была доказать тезис о том, что С++ настолько крут, что в нем все можно сделать в бибилотеке... и лямбду, и замыкание, и черта лысого.

Насчет черта лысого не уверен, но лямбда удалась на славу:


void MyF1(vector<int>& vec, int s)
{
    transform(vec.begin(), vec.end(), vec.begin(), (s + _1));
}



VC8.0 -O2


?MyF1@@YAXAAV?$vector@HV?$allocator@H@std@@@std@@H@Z PROC ; MyF1, COMDAT
    mov    eax, DWORD PTR _vec$[esp-4]
    mov    ecx, DWORD PTR [eax+4]
    mov    edx, DWORD PTR [eax+8]
    mov    eax, ecx
    cmp    eax, edx
    push    esi
    push    edi
    je    SHORT $LN71@MyF1
    mov    esi, DWORD PTR _s$[esp+4]
$LL82@MyF1:
    mov    edi, DWORD PTR [eax]
    add    edi, esi
    mov    DWORD PTR [ecx], edi
    add    eax, 4
    add    ecx, 4
    cmp    eax, edx
    jne    SHORT $LL82@MyF1
$LN71@MyF1:
    pop    edi
    pop    esi
    ret    0


Очень похоже на нулевые издержки.
Re[7]: BOOST, .NET, String.Split и производительность…
От: WolfHound  
Дата: 20.09.06 09:11
Оценка: +1 -1
Здравствуйте, Denis2005, Вы писали:

D>Насчет черта лысого не уверен, но лямбда удалась на славу:


D>
D>void MyF1(vector<int>& vec, int s)
D>{
D>    transform(vec.begin(), vec.end(), vec.begin(), (s + _1));
D>}
D>

Вот скажи мне на сколько часто тебе нужны такая лямюбда? Мне нужно как минимум обратится к челену класса, а с этим уже все не так красиво... А если нужно както так Obj.Prop1.Prop2.Prop3 то вобще тушите свет.
Короче для людей которые использовали нормальную лямбду очевидно что boost::lambda непригодно для реальной работы.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[8]: BOOST, .NET, String.Split и производительность…
От: Denis2005 Россия  
Дата: 20.09.06 10:17
Оценка: +2
Здравствуйте, WolfHound, Вы писали:

WH>Вот скажи мне на сколько часто тебе нужны такая лямюбда? Мне нужно как минимум обратится к челену класса, а с этим уже все не так красиво... А если нужно както так Obj.Prop1.Prop2.Prop3 то вобще тушите свет.

WH>Короче для людей которые использовали нормальную лямбду очевидно что boost::lambda непригодно для реальной работы.

Собственно говоря boost::lambda предназначен для того, чтобы не приходилось писать функции/функторы под простейшие случаи. Немогу не согласится, что для Obj.Prop1.Prop2.Prop3 это просто не пригодно. Вообщем более 'толстые' лямбды я все равно не пишу, предпочитаю функторы, т.к. это более декомпозиционно.
Re[3]: [Benchmark] DMD быстрее всех
От: cattus  
Дата: 20.09.06 10:19
Оценка:
C># g++ test_with_vector.cpp
C># ./a.out
C>res is/ 5000000,3117 ms elapsed

C># g++ -O3 test_with_vector.cpp

C># ./a.out
C>res is/ 5000000,756 ms elapsed

C># g++ test_with_deque.cpp

C># ./a.out
C>res is 5000000,2919 ms elapsed

C># g++ -O3 test_with_deque.cpp

C># ./a.out
C>res is 5000000,801 ms elapsed

C># g++ test_with_list.cpp

C># ./a.out
C>res is 5000000,2673 ms elapsed

C># g++ -O3 test_with_list.cpp

C># ./a.out
C>res is 5000000,653 ms elapsed

C># python test.py

C>res is 5000000, 2.100000 sec elapsed


Перед всеми извиняюсь, ляпнул.

#include <list>
#include <string>
#include <iostream>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>

#define OS_POSIX

#ifdef OS_WINDOWS
#include <windows.h> // for GetTickCount
#else // posix
#include <sys/times.h>
#endif

using namespace std;
using namespace boost::algorithm;

int main()
{
#ifdef OS_WINDOWS
  DWORD start = GetTickCount();
#else
  struct tms t;
  long ts = sysconf(_SC_CLK_TCK);
  double start = ((double) times(&t) / ts) * 1000;
#endif
    
  int res = 0;
  for(int i = 0; i < 1000000; i++)
  {
    list<string> tokens; 
    split(tokens, "123 345 asdf 23453 asdfas", is_any_of(" "));
    res += tokens.size();
  }


#ifdef OS_WINDOWS
  DWORD stop = GetTickCount();
#else
  double stop = ((double) times(&t) / ts) * 1000;
#endif

  cout << "res is " << res << ',' << stop - start << " ms elapsed\n";
  
  return 0;
}


Так как функция sysconf(_SC_CLK_TCK) (количество тиков в секунду) на моей машине возвращает 100, достаточно каждый из вышеприведённых результатов умножить на 10.

C># g++ test_with_vector.cpp

C># ./a.out
C>res is/ 5000000,31170 ms elapsed

C># g++ -O3 test_with_vector.cpp

C># ./a.out
C>res is/ 5000000,7560 ms elapsed

C># g++ test_with_deque.cpp

C># ./a.out
C>res is 5000000,29190 ms elapsed

C># g++ -O3 test_with_deque.cpp

C># ./a.out
C>res is 5000000,8010 ms elapsed

C># g++ test_with_list.cpp

C># ./a.out
C>res is 5000000,26730 ms elapsed

C># g++ -O3 test_with_list.cpp

C># ./a.out
C>res is 5000000,6530 ms elapsed

То есть лучший результат 6,530 сек.
Re[9]: BOOST, .NET, String.Split и производительность…
От: WolfHound  
Дата: 20.09.06 11:20
Оценка:
Здравствуйте, Denis2005, Вы писали:

D>Собственно говоря boost::lambda предназначен для того, чтобы не приходилось писать функции/функторы под простейшие случаи. Немогу не согласится, что для Obj.Prop1.Prop2.Prop3 это просто не пригодно. Вообщем более 'толстые' лямбды я все равно не пишу, предпочитаю функторы, т.к. это более декомпозиционно.

Что только люди не приюдумают для того чтобы оправдать использование С++.
По сравнению с нормальной лямбдой функторы не рулят совершенно.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[10]: BOOST, .NET, String.Split и производительность…
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 20.09.06 11:26
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Что только люди не приюдумают для того чтобы оправдать использование С++.




WH>По сравнению с нормальной лямбдой функторы не рулят совершенно.


Временами рулят и очень сильно. Функторы могут наследоваться. Функторы могут разрастаться до довольно таки сложной логики и приличного размера.

А вот boost::lambda по сравненю с нормальной лямбдой действительно и рядом не стояла.


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[11]: BOOST, .NET, String.Split и производительность…
От: WolfHound  
Дата: 20.09.06 11:53
Оценка:
Здравствуйте, eao197, Вы писали:

E>Временами рулят и очень сильно. Функторы могут наследоваться. Функторы могут разрастаться до довольно таки сложной логики и приличного размера.

Код в студию.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[11]: BOOST, .NET, String.Split и производительность…
От: Курилка Россия http://kirya.narod.ru/
Дата: 20.09.06 12:03
Оценка:
Здравствуйте, eao197, Вы писали:

E>Здравствуйте, WolfHound, Вы писали:


WH>>По сравнению с нормальной лямбдой функторы не рулят совершенно.


E>Временами рулят и очень сильно. Функторы могут наследоваться. Функторы могут разрастаться до довольно таки сложной логики и приличного размера.


Т.е. ты декомпозицию делаешь при помощи ООП? При функциональной декомпозиции это будет выглядеть иначе, наследование там вообще как понятие не существует.
Re[12]: BOOST, .NET, String.Split и производительность…
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 20.09.06 12:25
Оценка: :)))
Здравствуйте, WolfHound, Вы писали:

E>>Временами рулят и очень сильно. Функторы могут наследоваться. Функторы могут разрастаться до довольно таки сложной логики и приличного размера.

WH>Код в студию.

Вот, пример большого функтора:
/*!
    \since v.4.2.7
    \brief Предикат для std::find_if.

    Для очередного состояния проверяет возможность слияния
    с состоянием из другого класса агентов.

    Определяет, есть ли среди всех классов, на которые ссылаются
    состояния, еще не полностью определенные классы.
*/
class    merge_possibility_checker_t
    :    public std::unary_function<
            const state_handler_impl_ptr_vector_t::value_type &,
            bool >
    {
    private :
        /*! Список всех классов. */
        const class_map_t & m_all_classes;

        /*! Список состояний всех классов */
        const std_class_relation_handler_t::class_info_map_t &
            m_classes_state;

        /*! Принимает значение true, если были найдены не
            полностью определенные классы. */
        bool    & m_is_incomplete_class_found;

        /*! Приемник описания ошибки. */
        std::string &    m_error_desc;

    public :
        //! Основной конструктор.
        merge_possibility_checker_t(
            //! Список всех классов.
            const class_map_t & all_classes,
            const std_class_relation_handler_t::class_info_map_t &
                classes_state,
            bool & is_incomplete_class_found,
            //! Приемник описания ошибки.
            std::string & error_desc )
            :    m_is_incomplete_class_found( is_incomplete_class_found )
            ,    m_all_classes( all_classes )
            ,    m_classes_state( classes_state )
            ,    m_error_desc( error_desc )
            {}

        result_type
        operator()( argument_type a );

    private :
        /*! Проверка наличия указанного состояния в указанном
            классе.

            \return true, если состояние найдено. */
        bool
        try_find_state_in_class(
            //! Имя искомого состояния.
            const std::string & state_name,
            //! Класс, в котором состояние нужно найти.
            const class_handler_impl_t & class_handler );
    };

merge_possibility_checker_t::result_type
merge_possibility_checker_t::operator()( argument_type a )
    {
        bool result = false;

        const state_handler_impl_t::merge_list_t & merge_list =
            a->merge_list();

        for( state_handler_impl_t::merge_list_t::const_iterator
                it = merge_list.begin(), it_end = merge_list.end();
            it != it_end;
            ++it )
            {
                bool is_merge_valid = false;

                const state_handler_impl_t::merge_t & m = *it;

                // Должен быть известен класс.
                class_map_t::const_iterator it_class = m_all_classes.find(
                    m.m_class_name );
                if( it_class != m_all_classes.end() )
                    {
                        int state = m_classes_state.find(
                            m.m_class_name )->second.m_state;
                        // Класс должен быть полностью определен.
                        if( std_class_relation_handler_t::state_valid == state )
                            {
                                // Должно быть известно состояние.
                                if( try_find_state_in_class(
                                    m.m_state_name, *( it_class->second ) ) )
                                    // Все хорошо. Поэтому, чтобы перейти к обработке
                                    // следующего состояния, нужно возвратить false.
                                    is_merge_valid = true;
                                else
                                    {
                                        // Состояние не известно.
                                        m_error_desc += std::string( "state '" ) +
                                            a->query_name() +
                                            "' requires merging with undefined state '" +
                                            m.m_state_name + "' from class '" +
                                            m.m_class_name + "';";
                                    }
                            }
                        else if( std_class_relation_handler_t::state_invalid == state )
                            // Нашли ссылку на некорректный класс.
                            m_error_desc += std::string( "state '" ) +
                                a->query_name() +
                                "' requires merging with invalid class '" +
                                m.m_class_name + "';";
                        else
                            {
                                // Класс еще не определен.
                                m_is_incomplete_class_found = true;
                                m_error_desc += std::string( "incomplete class: " ) +
                                    m.m_class_name + ";";
                            }
                    }
                else
                    // Нашли ссылку на неизвестный класс.
                    m_error_desc += std::string( "state '" ) + a->query_name() +
                        "' requires merging with undefined class '" +
                        m.m_class_name + "';";

                // Если текущее слияние не корректно, то и состояние не может
                // быть корректным.
                if( !is_merge_valid )
                    result = true;
            }

        return result;
    }

bool
merge_possibility_checker_t::try_find_state_in_class(
    const std::string & state_name,
    const class_handler_impl_t & class_handler )
    {
        const state_handler_impl_ptr_vector_t & states =
            class_handler.query_state_handlers();
        return ( states.end() != std::find_if(
            states.begin(), states.end(),
            state_by_name_finder_t( state_name ) ) );
    }


который используется так:
int
std_class_relation_handler_t::try_merge_states(
    const class_handler_impl_t & class_handler,
    const class_map_t & all_classes,
    std::string & error_desc )
    {
        // Берем все состояния, которые нуждаются в слиянии.
        state_handler_impl_ptr_vector_t states_for_merging =
            class_handler.states_for_merge();

        // Проверяем возможность проведения слияния.
        bool is_incomplete_class_found = false;
        merge_possibility_checker_t checker( all_classes, m_classes,
            is_incomplete_class_found, error_desc );
        if( states_for_merging.end() != std::find_if(
            states_for_merging.begin(), states_for_merging.end(),
            checker ) )
            // Слияние не возможно. Осталось только определить,
            // по какой причине.
            return ( is_incomplete_class_found ?
                state_not_processed :
                state_invalid );

        // Выполняем слияние.
        std::for_each( states_for_merging.begin(),
            states_for_merging.end(),
            merge_maker_t( all_classes ) );

        return state_valid;
    }


По поводу наследования: в своих OpenSource проектах с ходу не нашел. А код из закрытых проектов не смотрел, т.к. результат все равно не смогу показать. Но раз или два пришлось делать наследование для функторов, чтобы общую функциональность в базовый класс поместить. Ну и простейший пример наследования для функторов -- наследование от std::unary_function .


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[12]: BOOST, .NET, String.Split и производительность…
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 20.09.06 12:30
Оценка:
Здравствуйте, Курилка, Вы писали:

E>>Временами рулят и очень сильно. Функторы могут наследоваться. Функторы могут разрастаться до довольно таки сложной логики и приличного размера.


К>Т.е. ты декомпозицию делаешь при помощи ООП? При функциональной декомпозиции это будет выглядеть иначе, наследование там вообще как понятие не существует.


Не очень понимаю, о чем ты. Мне просто пару раз над элементами контейнеров пришлось делать несколько похожих, но отличающихся в деталях операций (каких именно уже не помню). Поэтому я сделал базовый класс, наследник от std::unary_function, в нем пару виртуальных методов. Затем пару производных классов, в которых эти виртуальные методы перекрывались. А потом в коде вызывал std::for_each то с одним наследником, то с другим.


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[13]: BOOST, .NET, String.Split и производительность…
От: Курилка Россия http://kirya.narod.ru/
Дата: 20.09.06 12:40
Оценка: +2
Здравствуйте, eao197, Вы писали:

E>Здравствуйте, Курилка, Вы писали:


E>>>Временами рулят и очень сильно. Функторы могут наследоваться. Функторы могут разрастаться до довольно таки сложной логики и приличного размера.


К>>Т.е. ты декомпозицию делаешь при помощи ООП? При функциональной декомпозиции это будет выглядеть иначе, наследование там вообще как понятие не существует.


E>Не очень понимаю, о чем ты. Мне просто пару раз над элементами контейнеров пришлось делать несколько похожих, но отличающихся в деталях операций (каких именно уже не помню). Поэтому я сделал базовый класс, наследник от std::unary_function, в нем пару виртуальных методов. Затем пару производных классов, в которых эти виртуальные методы перекрывались. А потом в коде вызывал std::for_each то с одним наследником, то с другим.


О том, что если решать эту задачу с т.зр. ФП, то виртуальных методов не будет, а будет функция высшего порядка, в которую будут передаваться функции, которые соотвествуют твоим перекрытым методам.
Просто ты решал задачу в терминах объектов и тебе было так удобнее, кому-то возможно удобнее по-другому.
Re[14]: BOOST, .NET, String.Split и производительность…
От: Cyberax Марс  
Дата: 20.09.06 13:11
Оценка:
Курилка wrote:
> О том, что если решать эту задачу с т.зр. ФП, то виртуальных методов не
> будет, а будет функция высшего порядка, в которую будут передаваться
> функции, которые соотвествуют твоим перекрытым методам.
То же самое, вид сбоку.
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re[15]: BOOST, .NET, String.Split и производительность…
От: Курилка Россия http://kirya.narod.ru/
Дата: 20.09.06 13:28
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>Курилка wrote:

>> О том, что если решать эту задачу с т.зр. ФП, то виртуальных методов не
>> будет, а будет функция высшего порядка, в которую будут передаваться
>> функции, которые соотвествуют твоим перекрытым методам.
C>То же самое, вид сбоку.
Не спорю, просто кому-то удобней может быть такой вид, а кому-то наоборот
Re[7]: [Benchmark] DMD быстрее всех
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.09.06 14:29
Оценка:
Здравствуйте, _rasta, Вы писали:

_>ну вот зачем писать бред?


И я тоже думаю "зачем писать бред" но ты это делашь без зазрения.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: [Benchmark] DMD быстрее всех
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.09.06 14:29
Оценка:
Здравствуйте, Odi$$ey, Вы писали:

OE>ничего, что также изначально было

OE>C# (под той же виндой) — 1сек ?

Думаю, это не важно в контесте разговоров о вредоносности дяди Билла.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[11]: [Benchmark] DMD быстрее всех
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.09.06 14:29
Оценка:
Здравствуйте, _rasta, Вы писали:

_>я там смайлик забыл


В следущий раз не забывай. А то без него твои слова выглядят форменным бредом.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: BOOST, .NET, String.Split и производительность…
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.09.06 14:29
Оценка:
Здравствуйте, Denis2005, Вы писали:

D>Насчет черта лысого не уверен, но лямбда удалась на славу:


D>
D>void MyF1(vector<int>& vec, int s)
D>{
D>    transform(vec.begin(), vec.end(), vec.begin(), (s + _1));
D>}
D>


Да, уж на славу... для тех кто нормальной не видел. _1 уже круто. А возьми случаи чуть по сложнее и ты приплыл. Ведь лямбды хороши тем, что это фукнции высшего порядка которые можно комбинировать.

Да и проблем с ними не оберешся. В языках где они реализовны нормально, они имеют лексическую область видимости и их время жизни оеределяется наличием ссылок на них. Тут же фиг. А на дисерт пиколы вроде ничаянного добавления переменной с именем _1 в локальную область видимости, невнятные сообщения об ошибках и т.п.

Кстати, даже в такх, примитивных, случаях языки с полноценной поддержкой функций высшего порядка выглядят лучше.
Вот как это будет выглядить не Немерле:
transform.(s + _);

"s + _" автоматом преобразуется в лямбду с одним параметром (никаких лишних скобок и хардкодед-имен вроде "_1" не нужно). Да и отсуствие идиотизма с begin()/end() разгружает код. В итоге получается, что писать функционально конечно на С++ можно, но неудобно, не всегда быстро, и очень громоздко.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: BOOST, .NET, String.Split и производительность…
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.09.06 14:29
Оценка:
Здравствуйте, Denis2005, Вы писали:

D>Собственно говоря boost::lambda предназначен для того, чтобы не приходилось писать функции/функторы под простейшие случаи. Немогу не согласится, что для Obj.Prop1.Prop2.Prop3 это просто не пригодно. Вообщем более 'толстые' лямбды я все равно не пишу, предпочитаю функторы, т.к. это более декомпозиционно.


Для тех кто плотно попользовался функцями высшего порядка (ФВП), лямбды и локальные фукнции становятся частью средств декомпозиции кода и они начинают применяться повсеместно. Не важно насколько сложен случай. Уж обращаться к членам классов точно постоянно нужно (особенно в императивном С++).
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[11]: BOOST, .NET, String.Split и производительность…
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.09.06 14:29
Оценка:
Здравствуйте, eao197, Вы писали:

E>Временами рулят и очень сильно. Функторы могут наследоваться. Функторы могут разрастаться до довольно таки сложной логики и приличного размера.


А что классы в других языках отменили что ли? Просто в других языках нет нужны эмулировать классами функции высшего порядка. Они уже есть в языке шататно.

И тебе ли это не знать? Снова поспорить охота?
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[12]: BOOST, .NET, String.Split и производительность…
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.09.06 14:29
Оценка:
Здравствуйте, Курилка, Вы писали:

К>Т.е. ты декомпозицию делаешь при помощи ООП? При функциональной декомпозиции это будет выглядеть иначе, наследование там вообще как понятие не существует.


Он на Руби пишет, в лучшем случае. А там как и в С++ ООП основное средство декомпозиции. Других практически нет. Одними лямбдами (блоками) сыт не будешь.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.