Форум программистов, компьютерный форум CyberForum.ru

Какова польза лямбда выражений - C++

Восстановить пароль Регистрация
 
 
Рейтинг: Рейтинг темы: голосов - 9, средняя оценка - 4.67
volodja-
0 / 0 / 0
Регистрация: 17.03.2014
Сообщений: 13
17.03.2014, 13:05     Какова польза лямбда выражений #1
Вот набросал пример который показывает что лямбда выражения медленней простых циклов и больше кода, в чем тогда их польза ?

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*
 * main.cpp
 *
 *  Created on: 31 янв. 2014 г.
 *      Author: volodja
 */
 
 
 
 
#include <iostream>
#include <vector>
#include <algorithm>
#include <stdint.h>
#include <time.h>
#include <sys/time.h>
#include <string>
 
 
#include "stopwatch.h"
 
 
using namespace std;
 
 
timeval getCurrentTime() {
    timeval current_time;
    gettimeofday(&current_time, NULL);
    return  current_time;
}
 
 
uint64_t getElapsedMicrosecond(const timeval &stopwatch_time) {
    timeval current_time = getCurrentTime();
    return (current_time.tv_sec - stopwatch_time.tv_sec) * 1000000 + current_time.tv_usec - stopwatch_time.tv_usec;
}
 
 
vector<char> testCopy() {
    vector<char>    result;
    char            ch = 0;
 
    for (size_t i = 0; i < 10; i++) {
        ch++;
        result.push_back(ch);
    }
 
    return result;
}
 
 
vector<char>&& testMove() {
    vector<char>    result;
    char            ch = 0;
 
    for (size_t i = 0; i < 10; i++) {
        ch++;
        result.push_back(ch);
    }
 
    return move(result);
}
 
 
void testMoveVsCopy() {
    timeval         stopwatch_time;
    const size_t    count = 1000000;
    vector<char>    v;
 
    {
        cout << "copy: " << endl;
        stopwatch_time = getCurrentTime();
        for (size_t i = 0; i < count; i++)
            v.push_back(testCopy()[i % 100]);
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    {
        cout << "copy lambda: " << endl;
        stopwatch_time = getCurrentTime();
        size_t i = 0;
        generate_n(back_inserter(v), count,
            [&i]() -> char {
                i++;
                return testCopy()[i % 100];
            }
        );
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    {
        cout << "move: " << endl;
        stopwatch_time = getCurrentTime();
        for (size_t i = 0; i < count; i++)
            v.push_back(testMove()[i % 100]);
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    {
        cout << "move lambda: " << endl;
        stopwatch_time = getCurrentTime();
        size_t i = 0;
        generate_n(back_inserter(v), count,
            [&i]() -> char {
                i++;
                return testMove()[i % 100];
            }
        );
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
}
 
 
//void executeLambda([](const int &i) -> double) {
//
//}
 
 
void testLambda() {
    int a = 1, b = 2;
    cout << "b = " << b << endl;
    [=, &b]{
        b = b + a;
    }();
    cout << "b = " << b << endl;
 
}
 
 
int main() {
    testMoveVsCopy();
 
    testLambda();
 
    return 0;
}
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
17.03.2014, 13:05     Какова польза лямбда выражений
Посмотрите здесь:

Лямбда выражения C++
C++ лямбда заполнения вектора
Передача лямбда в функции C++
C++ лямбда функция
С++11 Лямбда-выражения и вывод результата C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Croessmah
Модератор
Эксперт С++
 Аватар для Croessmah
11800 / 6779 / 765
Регистрация: 27.09.2012
Сообщений: 16,829
Записей в блоге: 2
Завершенные тесты: 1
17.03.2014, 13:09     Какова польза лямбда выражений #2
А может нужно научиться готовить их?
DrOffset
6416 / 3790 / 876
Регистрация: 30.01.2014
Сообщений: 6,575
17.03.2014, 13:25     Какова польза лямбда выражений #3
Фраза
Цитата Сообщение от volodja- Посмотреть сообщение
лямбда выражения медленней простых циклов
звучит как "удобрения медленнее лопаты". Абсурд не правда ли?
Сами по себе лямбда выражения - это синтаксический сахар для функторов. В С++ до этого не существовало способа сделать анонимный функтор, теперь такой способ есть, + некоторые плюшки (вроде захвата переменных). То, что ты там в своем примере заюзал стандартные алгоритмы с таким функтором и получил просадку производительности по сравнению с голым циклом, вообще никак лямбды не характеризует. Характеризует только то, что тест некорректный.
volodja-
0 / 0 / 0
Регистрация: 17.03.2014
Сообщений: 13
17.03.2014, 13:33  [ТС]     Какова польза лямбда выражений #4
в чем не корректность теста ?
И что тогда лучше использовать в местах с простыми циклами, лямбда или циклы(итераторы) ?
Еще так к месту, конструкторы перемещения дают очень небольшой прирост производительности (в 1,04873245 раза).
Использовал самые простые конструкции, может быть лямбда можно как-то лучше приготовить ?
Croessmah
Модератор
Эксперт С++
 Аватар для Croessmah
11800 / 6779 / 765
Регистрация: 27.09.2012
Сообщений: 16,829
Записей в блоге: 2
Завершенные тесты: 1
17.03.2014, 13:35     Какова польза лямбда выражений #5
Цитата Сообщение от volodja- Посмотреть сообщение
дают очень небольшой прирост производительности
ну попробуйте скопировать и переместить вектор из 100000000 объектов
DrOffset
6416 / 3790 / 876
Регистрация: 30.01.2014
Сообщений: 6,575
17.03.2014, 13:40     Какова польза лямбда выражений #6
Цитата Сообщение от volodja- Посмотреть сообщение
в чем не корректность теста ?
В том, что ты сравниваешь совершенно разные подходы к решению задачи. Выбрав при этом условия задачи такими, что подход с голыми циклами оказывается быстрее. Для корректности нужно было сравнивать лямбды с обычными С++ функторами (которые классы).

Цитата Сообщение от volodja- Посмотреть сообщение
И что тогда лучше использовать в местах с простыми циклами
От задачи зависит. И от целей. Озвучь конкретную задачу, будем ее рассматривать.
И еще раз скажу, лямбды - это функторы (то есть функциональные объекты, то есть объекты, которые ведут себя как функции). Ее совсем не обязательно в цикл пихать.

Цитата Сообщение от volodja- Посмотреть сообщение
конструкторы перемещения дают очень небольшой прирост производительности (в 1,04873245 раза).
А это зависит от характера данных. Нельзя так просто в общем случае утверждать.
volodja-
0 / 0 / 0
Регистрация: 17.03.2014
Сообщений: 13
17.03.2014, 13:41  [ТС]     Какова польза лямбда выражений #7
А цикл быстрее лямбда быстрее в 1,240681149 раза (видимо за счет создания временной структуры в каждой итерации).
DrOffset
6416 / 3790 / 876
Регистрация: 30.01.2014
Сообщений: 6,575
17.03.2014, 13:43     Какова польза лямбда выражений #8
Цитата Сообщение от volodja- Посмотреть сообщение
А цикл быстрее лямбда
Не цикл быстрее лямбды, а цикл быстрее подхода с использованием стандартного алгоритма в этой конкретной ситуации.
volodja-
0 / 0 / 0
Регистрация: 17.03.2014
Сообщений: 13
17.03.2014, 13:54  [ТС]     Какова польза лямбда выражений #9
Цитата Сообщение от DrOffset Посмотреть сообщение
А это зависит от характера данных. Нельзя так просто в общем случае утверждать.
В данном тесте я проверял только скорость передачи данных из локальной области видимости во внешнюю область видимости (фактически скорость return), данные не суть важно какие, просто небольшой массив байт. Не думаю что из безымянных структур можно создавать какие-то сложные конструкции, по этому предполагаю что лямда и подразумевает использование в небольших локальных конструкциях с stl.algorithm.

Добавлено через 5 минут
Цитата Сообщение от DrOffset Посмотреть сообщение
Для корректности нужно было сравнивать лямбды с обычными С++ функторами (которые классы).
Смысла нет, т.к. это одно и тоже только по разному записано, т.е. лямда при компиляции преобразуется в класс.
Croessmah
Модератор
Эксперт С++
 Аватар для Croessmah
11800 / 6779 / 765
Регистрация: 27.09.2012
Сообщений: 16,829
Записей в блоге: 2
Завершенные тесты: 1
17.03.2014, 14:02     Какова польза лямбда выражений #10
Цитата Сообщение от volodja- Посмотреть сообщение
данные не суть важно какие
просто для примера:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
struct TEST {
   TEST ( ) {
      std::cout << "create test object" << std::endl ;
   }
   TEST ( const TEST & ) {
      std::cout << "copy test object" << std::endl ;
   }
   ~TEST ( ) {
      std::cout << "delete test object" << std::endl ;
   }
} ;
 
 
int main () {
   std::vector<TEST> vec1(5) ;
   std::cout << "BEGIN\nCopy:\n" ;
   std::vector<TEST> vec2 (vec1);
   std::cout << "Move:\n" ;
   std::vector<TEST> vec3 (std::move ( vec1 ) );
   std::cout << "END" << std::endl ;
}
Вы вообще сравниваете теплое с мягким
volodja-
0 / 0 / 0
Регистрация: 17.03.2014
Сообщений: 13
17.03.2014, 14:21  [ТС]     Какова польза лямбда выражений #11
В моем примере оптимизация компилятора почти что уравнивает по скорости конструктор копирования и перемещения при возврате результата, по этому разница в скорости различима только для циклов и лямбда.
Вывод в консоль такой (gcc 4.7.3):

copy:
182104
copy lambda:
225933
move:
173642
move lambda:
222386
Croessmah
Модератор
Эксперт С++
 Аватар для Croessmah
11800 / 6779 / 765
Регистрация: 27.09.2012
Сообщений: 16,829
Записей в блоге: 2
Завершенные тесты: 1
17.03.2014, 14:36     Какова польза лямбда выражений #12
Цитата Сообщение от volodja- Посмотреть сообщение
В моем примере оптимизация компилятора почти что уравнивает по скорости конструктор копирования и перемещения при возврате результата
В Вашем примере большая часть теста не корректна
Croessmah
Модератор
Эксперт С++
 Аватар для Croessmah
11800 / 6779 / 765
Регистрация: 27.09.2012
Сообщений: 16,829
Записей в блоге: 2
Завершенные тесты: 1
17.03.2014, 14:55     Какова польза лямбда выражений #13
Чуть поменял, чтобы не было автоматических переменных в некоторых местах, которые будут не копироваться, а перемещаться
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include <iostream>
#include <vector>
#include <algorithm>
#include <stdint.h>
#include <time.h>
#include <sys/time.h>
#include <string>
 
 
 
using namespace std;
 
 
timeval getCurrentTime() {
    timeval current_time;
    gettimeofday(&current_time, NULL);
    return  current_time;
}
 
 
uint64_t getElapsedMicrosecond(const timeval &stopwatch_time) {
    timeval current_time = getCurrentTime();
    return (current_time.tv_sec - stopwatch_time.tv_sec) * 1000000 + current_time.tv_usec - stopwatch_time.tv_usec;
}
 
 
vector<char> testCopy( vector<char> & result ) {
 
    char            ch = 0;
 
    for (size_t i = 0; i < 100000; i++) {
        ch++;
        result.push_back(ch);
    }
 
    return result;
}
 
 
vector<char> testMove(vector<char>  &result) {
    char            ch = 0;
 
    for (size_t i = 0; i < 10000; i++) {
        ch++;
        result.push_back(ch);
    }
 
    return move(result);
}
 
 
void testMoveVsCopy() {
    timeval         stopwatch_time;
    const size_t    count = 1000;
    vector<char>    v;
 
    {vector<char>    v2;
        cout << "copy: " << endl;
        stopwatch_time = getCurrentTime();
        for (size_t i = 0; i < count; i++)
            v.push_back(testCopy(v2)[0]);
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    {vector<char>    v2;
        cout << "copy lambda: " << endl;
        stopwatch_time = getCurrentTime();
        size_t i = 0;
        generate_n(back_inserter(v), count,
            [&i,&v2]() -> char {
                i++;
                return testCopy(v2)[0];
            }
        );
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    {vector<char>    v2;
        cout << "move: " << endl;
        stopwatch_time = getCurrentTime();
        for (size_t i = 0; i < count; i++)
            v.push_back(testMove(v2)[0]);
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    {vector<char>    v2;
        cout << "move lambda: " << endl;
        stopwatch_time = getCurrentTime();
        size_t i = 0;
        generate_n(back_inserter(v), count,
            [&i,&v2]() -> char {
                i++;
                return testMove(v2)[0];
            }
        );
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
}
 
 
//void executeLambda([](const int &i) -> double) {
//
//}
 
 
void testLambda() {
    int a = 1, b = 2;
    cout << "b = " << b << endl;
    [=, &b]{
        b = b + a;
    }();
    cout << "b = " << b << endl;
 
}
 
 
int main() {
    testMoveVsCopy();
 
    testLambda();
 
    return 0;
}
Результаты:
Какова польза лямбда выражений
Croessmah
Модератор
Эксперт С++
 Аватар для Croessmah
11800 / 6779 / 765
Регистрация: 27.09.2012
Сообщений: 16,829
Записей в блоге: 2
Завершенные тесты: 1
17.03.2014, 14:58     Какова польза лямбда выражений #14
Еще вопросы по эффективности перемещения имеются?
volodja-
0 / 0 / 0
Регистрация: 17.03.2014
Сообщений: 13
17.03.2014, 15:50  [ТС]     Какова польза лямбда выражений #15
в общем разъяснил ситуацию лямбда, результат прямо противоположный:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
/*
 * main.cpp
 *
 *  Created on: 31 янв. 2014 г.
 *      Author: volodja
 */
 
 
 
 
#include <iostream>
#include <vector>
#include <algorithm>
#include <stdint.h>
#include <time.h>
#include <sys/time.h>
#include <string>
 
 
using namespace std;
 
 
timeval getCurrentTime() {
    timeval current_time;
    gettimeofday(&current_time, NULL);
    return  current_time;
}
 
 
uint64_t getElapsedMicrosecond(const timeval &stopwatch_time) {
    timeval current_time = getCurrentTime();
    return (current_time.tv_sec - stopwatch_time.tv_sec) * 1000000 + current_time.tv_usec - stopwatch_time.tv_usec;
}
 
 
void testLambdaVsFor() {
    const size_t    count = 100000000;
    vector<char>    data;
    timeval         stopwatch_time;
    char            ch = 0;
 
    cout << "data pushback " << endl;
    {
        cout << "  lambda:" << endl;
        stopwatch_time = getCurrentTime();
        data.resize(count);
        generate(data.begin(), data.end(), [&ch]() {return ch++;} );
        cout << "  " << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    data.clear();
 
    {
        cout << "  lambda back_inserter:" << endl;
        stopwatch_time = getCurrentTime();
        generate_n(back_inserter(data), count, [&ch]() {return ch++;} );
        cout << "  " << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    data.clear();
 
    {
        cout << "  for counter:" << endl;
        stopwatch_time = getCurrentTime();
        for (size_t i = 0; i < count; i++)
            data.push_back(ch++);
        cout << "  " << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    cout << "data modify" << endl;
    {
        cout << "  lambda:" << endl;
        stopwatch_time = getCurrentTime();
        std::for_each(data.begin(), data.end(), [](char &ch) {ch++;} );
        cout << "  " << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    {
        cout << "  for iterator:" << endl;
        stopwatch_time = getCurrentTime();
        for (auto i = data.begin(); i != data.end(); i++)
            (*i)++;
        cout << "  " << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    {
        cout << "  for counter:" << endl;
        stopwatch_time = getCurrentTime();
        for (size_t i = 0; i < data.size(); i++)
            data[i]++;
        cout << "  " << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
}
 
 
int main() {
    testLambdaVsFor();
 
    return 0;
}
вывод:
data pushback
lambda:
53000
lambda back_inserter:
194452
for counter:
220521
data modify
lambda:
10275
for iterator:
61350
for counter:
120558

Добавлено через 6 минут
Цитата Сообщение от Croessmah Посмотреть сообщение
Чуть поменял, чтобы не было автоматических переменных в некоторых местах, которые будут не копироваться, а перемещаться
Скомпилено с оптимизацией без дебага ?
Croessmah
Модератор
Эксперт С++
 Аватар для Croessmah
11800 / 6779 / 765
Регистрация: 27.09.2012
Сообщений: 16,829
Записей в блоге: 2
Завершенные тесты: 1
17.03.2014, 15:53     Какова польза лямбда выражений #16
Цитата Сообщение от volodja- Посмотреть сообщение
Скомпилено с оптимизацией без дебага ?
Release.
У Вас вектора были локальными и при возврате они перемещались, а не копировались, а в testMove, вы вообще ссылку возвращали
0x10
2425 / 1597 / 232
Регистрация: 24.11.2012
Сообщений: 3,919
17.03.2014, 15:54     Какова польза лямбда выражений #17
volodja-, в одном случае для вектора сразу сделан resize, в другом - вставка back_inserter'ом, и, как следствие, перевыделения памяти и копирования объектов. В общем, я не понимаю что вы пытаетесь измерить.
Croessmah
Модератор
Эксперт С++
 Аватар для Croessmah
11800 / 6779 / 765
Регистрация: 27.09.2012
Сообщений: 16,829
Записей в блоге: 2
Завершенные тесты: 1
17.03.2014, 16:04     Какова польза лямбда выражений #18
Цитата Сообщение от 0x10 Посмотреть сообщение
и, как следствие, перевыделения памяти и копирования объектов.
ну перевыделения врядли будут, ибо data.clear() лишь очищает вектор, но не освобождает память и выделенного куска хватит для следующего теста
Цитата Сообщение от 0x10 Посмотреть сообщение
в одном случае для вектора сразу сделан resize, в другом - вставка back_inserter'ом
угу, поэтому
Цитата Сообщение от 0x10 Посмотреть сообщение
В общем, я не понимаю что вы пытаетесь измерить.
ответ - теплое с мягким. Сравнивает изменение элементов(generate) с их вставкой(push_back)
volodja-
0 / 0 / 0
Регистрация: 17.03.2014
Сообщений: 13
17.03.2014, 16:05  [ТС]     Какова польза лямбда выражений #19
Согласен, пункт lambda: 53000 можно отбросить, не нашел пока способа вызывать push_back из лямбда. Но пункты в data modify выглядят достоверно.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
17.03.2014, 16:09     Какова польза лямбда выражений
Еще ссылки по теме:

C++ Отладчики - какая от них польза и как ими правильно пользоваться?
Почему не работают лямбда-выражения? C++
C++ Рекурсивная лямбда

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
Croessmah
Модератор
Эксперт С++
 Аватар для Croessmah
11800 / 6779 / 765
Регистрация: 27.09.2012
Сообщений: 16,829
Записей в блоге: 2
Завершенные тесты: 1
17.03.2014, 16:09     Какова польза лямбда выражений #20
Цитата Сообщение от volodja- Посмотреть сообщение
Но пункты в data modify выглядят достоверно.
а если так?
C++
1
2
3
4
5
        cout << "  for counter:" << endl;
        stopwatch_time = getCurrentTime();
        for (char * p = data.data(), * pend = p+data.size(); p<pend; ++p)
            (*p)++;
        cout << "  " << getElapsedMicrosecond(stopwatch_time) << endl;
Yandex
Объявления
17.03.2014, 16:09     Какова польза лямбда выражений
Ответ Создать тему
Опции темы

Текущее время: 01:24. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru