Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.79/19: Рейтинг темы: голосов - 19, средняя оценка - 4.79
0 / 0 / 0
Регистрация: 17.03.2014
Сообщений: 13
1

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

17.03.2014, 13:05. Показов 3987. Ответов 31
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Вот набросал пример который показывает что лямбда выражения медленней простых циклов и больше кода, в чем тогда их польза ?

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;
}
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
17.03.2014, 13:05
Ответы с готовыми решениями:

Использование лямбда-выражений в STL
Где dictionary - вектор, word1,word2 - string слова for(size_t i = 0; i &lt; word2.length(); ++i) ...

Поддержка лямбда-выражений
public interface MyNameIn { int GetValue(); } class LambdaDemo { public static void main(String...

Дебаггинг анонимных методов и лямбда-выражений
Добрый вечер. Написал свой первый более-менее серьезный и полезный проект на C# и уперся в...

Переопределить метод ToString() на основе лямбда-выражений
Хай. Нужно переопределить метод ToString() на основе лямбда-выражений. Подскажите, пожалуйста, как...

31
Неэпический
17870 / 10635 / 2054
Регистрация: 27.09.2012
Сообщений: 26,737
Записей в блоге: 1
17.03.2014, 13:09 2
А может нужно научиться готовить их?
0
18842 / 9841 / 2409
Регистрация: 30.01.2014
Сообщений: 17,284
17.03.2014, 13:25 3
Фраза
Цитата Сообщение от volodja- Посмотреть сообщение
лямбда выражения медленней простых циклов
звучит как "удобрения медленнее лопаты". Абсурд не правда ли?
Сами по себе лямбда выражения - это синтаксический сахар для функторов. В С++ до этого не существовало способа сделать анонимный функтор, теперь такой способ есть, + некоторые плюшки (вроде захвата переменных). То, что ты там в своем примере заюзал стандартные алгоритмы с таким функтором и получил просадку производительности по сравнению с голым циклом, вообще никак лямбды не характеризует. Характеризует только то, что тест некорректный.
1
0 / 0 / 0
Регистрация: 17.03.2014
Сообщений: 13
17.03.2014, 13:33  [ТС] 4
в чем не корректность теста ?
И что тогда лучше использовать в местах с простыми циклами, лямбда или циклы(итераторы) ?
Еще так к месту, конструкторы перемещения дают очень небольшой прирост производительности (в 1,04873245 раза).
Использовал самые простые конструкции, может быть лямбда можно как-то лучше приготовить ?
0
Неэпический
17870 / 10635 / 2054
Регистрация: 27.09.2012
Сообщений: 26,737
Записей в блоге: 1
17.03.2014, 13:35 5
Цитата Сообщение от volodja- Посмотреть сообщение
дают очень небольшой прирост производительности
ну попробуйте скопировать и переместить вектор из 100000000 объектов
0
18842 / 9841 / 2409
Регистрация: 30.01.2014
Сообщений: 17,284
17.03.2014, 13:40 6
Цитата Сообщение от volodja- Посмотреть сообщение
в чем не корректность теста ?
В том, что ты сравниваешь совершенно разные подходы к решению задачи. Выбрав при этом условия задачи такими, что подход с голыми циклами оказывается быстрее. Для корректности нужно было сравнивать лямбды с обычными С++ функторами (которые классы).

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

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

Добавлено через 5 минут
Цитата Сообщение от DrOffset Посмотреть сообщение
Для корректности нужно было сравнивать лямбды с обычными С++ функторами (которые классы).
Смысла нет, т.к. это одно и тоже только по разному записано, т.е. лямда при компиляции преобразуется в класс.
0
Неэпический
17870 / 10635 / 2054
Регистрация: 27.09.2012
Сообщений: 26,737
Записей в блоге: 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 ;
}
Вы вообще сравниваете теплое с мягким
1
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
0
Неэпический
17870 / 10635 / 2054
Регистрация: 27.09.2012
Сообщений: 26,737
Записей в блоге: 1
17.03.2014, 14:36 12
Цитата Сообщение от volodja- Посмотреть сообщение
В моем примере оптимизация компилятора почти что уравнивает по скорости конструктор копирования и перемещения при возврате результата
В Вашем примере большая часть теста не корректна
0
Неэпический
17870 / 10635 / 2054
Регистрация: 27.09.2012
Сообщений: 26,737
Записей в блоге: 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;
}
Результаты:
Какова польза лямбда выражений
1
Неэпический
17870 / 10635 / 2054
Регистрация: 27.09.2012
Сообщений: 26,737
Записей в блоге: 1
17.03.2014, 14:58 14
Еще вопросы по эффективности перемещения имеются?
0
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 Посмотреть сообщение
Чуть поменял, чтобы не было автоматических переменных в некоторых местах, которые будут не копироваться, а перемещаться
Скомпилено с оптимизацией без дебага ?
0
Неэпический
17870 / 10635 / 2054
Регистрация: 27.09.2012
Сообщений: 26,737
Записей в блоге: 1
17.03.2014, 15:53 16
Цитата Сообщение от volodja- Посмотреть сообщение
Скомпилено с оптимизацией без дебага ?
Release.
У Вас вектора были локальными и при возврате они перемещались, а не копировались, а в testMove, вы вообще ссылку возвращали
0
3257 / 2059 / 351
Регистрация: 24.11.2012
Сообщений: 4,909
17.03.2014, 15:54 17
volodja-, в одном случае для вектора сразу сделан resize, в другом - вставка back_inserter'ом, и, как следствие, перевыделения памяти и копирования объектов. В общем, я не понимаю что вы пытаетесь измерить.
0
Неэпический
17870 / 10635 / 2054
Регистрация: 27.09.2012
Сообщений: 26,737
Записей в блоге: 1
17.03.2014, 16:04 18
Цитата Сообщение от 0x10 Посмотреть сообщение
и, как следствие, перевыделения памяти и копирования объектов.
ну перевыделения врядли будут, ибо data.clear() лишь очищает вектор, но не освобождает память и выделенного куска хватит для следующего теста
Цитата Сообщение от 0x10 Посмотреть сообщение
в одном случае для вектора сразу сделан resize, в другом - вставка back_inserter'ом
угу, поэтому
Цитата Сообщение от 0x10 Посмотреть сообщение
В общем, я не понимаю что вы пытаетесь измерить.
ответ - теплое с мягким. Сравнивает изменение элементов(generate) с их вставкой(push_back)
0
0 / 0 / 0
Регистрация: 17.03.2014
Сообщений: 13
17.03.2014, 16:05  [ТС] 19
Согласен, пункт lambda: 53000 можно отбросить, не нашел пока способа вызывать push_back из лямбда. Но пункты в data modify выглядят достоверно.
0
Неэпический
17870 / 10635 / 2054
Регистрация: 27.09.2012
Сообщений: 26,737
Записей в блоге: 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;
0
17.03.2014, 16:09
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
17.03.2014, 16:09
Помогаю со студенческими работами здесь

В чем разница лямбда-выражений и анонимных методов?
В книге Шидта приводится два способа создания анонимных функций: 1) с использованием ключевого...

Программа с использованием делегатов, анонимных методов и лямбда-выражений
помогите с кодом программы. условие программы: с использованием делегата следующего вида delegate...

Реализовать с применением функционалов и лямбда-выражений следующую функцию
Здравстуйте, помогите решить задачку: &quot;Реализовать с применением функционалов и лямбда-выражений...

Реализовать заданные функции при помощи лямбда-выражений
Здравствуйте, помогите, пожалуйста реализовать следующие функции при помощи лямбда выражений: ...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru