Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.67/12: Рейтинг темы: голосов - 12, средняя оценка - 4.67
 Аватар для bedvit
1208 / 259 / 22
Регистрация: 20.05.2016
Сообщений: 1,136
Записей в блоге: 21

Оптимизировать ThreadPool на 8 потоков и задач

02.05.2023, 21:06. Показов 2792. Ответов 55
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Мое почтение, джентльмены.
Все работает, но хочу оптимизировать код, к примеру, для 8 потоков и задач.
Слишком долго выполняется на малых объёмах вычислений, собственно поэтому и хочу реализовать ThreadPool.
Из задуманного, удалить стек/очередь std::queue и операции std::move, tasks.pop(), tasks.emplace, возможно что-то еще.
Я точно знаю. что буду запускать количество потоков и задач = std::thread::hardware_concurrency() (количеству логических ядер), поэтому очередь не нужна (будет фикс блок все время). Прошу поделится вашей реализацией или годным советом.


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
#include <vector>
#include <queue>
#include <memory>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <future>
#include <functional>
#include <stdexcept>
#include <type_traits>
 
 
 
class ThreadPool {
public:
    ThreadPool(size_t);
    template<class F, class... Args>
    auto enqueue(F&& f, Args&&... args)
        -> std::future<typename std::invoke_result<F,Args...>::type>;
    ~ThreadPool();
private:
    // need to keep track of threads so we can join them
    std::vector< std::thread > workers;
    // the task queue
    std::queue< std::function<void()> > tasks;
 
    // synchronization
    std::mutex queue_mutex;
    std::condition_variable condition;
    bool stop;
};
 
// the constructor just launches some amount of workers
inline ThreadPool::ThreadPool(size_t threads)
    : stop(false)
{
    for (size_t i = 0; i < threads; ++i)
        workers.emplace_back(
            [this]
            {
                for (;;)
                {
                    std::function<void()> task;
 
                    {
                        std::unique_lock<std::mutex> lock(this->queue_mutex);
                        this->condition.wait(lock,
                            [this] { return this->stop || !this->tasks.empty(); });
                        if (this->stop && this->tasks.empty())
                            return;
                        task = std::move(this->tasks.front());
                        this->tasks.pop();
                    }
 
                    task();
                }
            }
            );
}
 
// add new work item to the pool
template<class F, class... Args>
auto ThreadPool::enqueue(F&& f, Args&&... args)
-> std::future<typename std::invoke_result<F,Args...>::type>
{
    using return_type = typename std::invoke_result<F,Args...>::type;
 
    auto task = std::make_shared< std::packaged_task<return_type()> >(
        std::bind(std::forward<F>(f), std::forward<Args>(args)...)
        );
 
    std::future<return_type> res = task->get_future();
    {
        std::unique_lock<std::mutex> lock(queue_mutex);
 
        // don't allow enqueueing after stopping the pool
        if (stop)
            throw std::runtime_error("enqueue on stopped ThreadPool");
 
        tasks.emplace([task]() { (*task)(); });
    }
    condition.notify_one();
    return res;
}
 
// the destructor joins all threads
inline ThreadPool::~ThreadPool()
{
    {
        std::unique_lock<std::mutex> lock(queue_mutex);
        stop = true;
    }
    condition.notify_all();
    for (std::thread& worker : workers)
        worker.join();
}
 
 
 
//...в реализации...
int coresCount=8;
std::vector<std::future<int>> thr(coresCount);
//...
thr[treadN]=pool.enqueue(...);
//...
Код взят отсюда.

Добавлено через 8 минут
В конструкторе своего класса
C++
1
ThreadPool pool (8);
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
02.05.2023, 21:06
Ответы с готовыми решениями:

Ручное управление количеством потоков в ThreadPool
Картина такая: есть некое приложение, которое может внутри себя наплодить до 1к потоков через Task.Start, для общения с сетевыми девайсами....

Сканирование портов в несколько потоков с помощью ThreadPool
Мне необходимо создать приложение в котором вводится определенное количество потоков которые сканируют порты. Как создать? ...

Ограниченное количество одновременно работающих потоков без ThreadPool
К делу. Так это работает в ThreadPool ThreadPool.QueueUserWorkItem(clientObject.Process); ThreadPool.SetMaxThreads(3, 3); Как это...

55
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
02.05.2023, 21:15
Цитата Сообщение от bedvit Посмотреть сообщение
Из задуманного, удалить стек/очередь std::queue и операции std::move, tasks.pop(), tasks.emplace, возможно что-то еще.
Зачем?
Цитата Сообщение от bedvit Посмотреть сообщение
Я точно знаю. что буду запускать количество потоков и задач = std::thread::hardware_concurrency() (количеству логических ядер), поэтому очередь не нужна
Одно с другим не связано.
Цитата Сообщение от bedvit Посмотреть сообщение
будет фикс блок все время
Вам что-то типа std::barrier нужно?
Опишите решаемую задачу.
0
 Аватар для bedvit
1208 / 259 / 22
Регистрация: 20.05.2016
Сообщений: 1,136
Записей в блоге: 21
02.05.2023, 21:26  [ТС]
zayats80888, хочу ускорить код. Добавление в очередь, удаление, перемещение - это все нужно если у меня сервер с 256 ядрамт и куча задач. У меня не так. У меня класс, функционал которого всегда будет на локальном ПК иметь, к примеру, 8 потоков и 8 задач. Мне нужно запустить 8 потоков, выполнить, получить данные, еще раз запустить 8 потоков в другом методе и т.д. Привязать номер потока к задаче или еще как то оптимизировать очередь.
0
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
02.05.2023, 22:33
Лучший ответ Сообщение было отмечено bedvit как решение

Решение

Цитата Сообщение от bedvit Посмотреть сообщение
Добавление в очередь, удаление, перемещение - это все нужно если у меня сервер с 256 ядрамт и куча задач.
Я к тому, что количество ядер/потоков не связано с очередью. Очередь только для распределения задач.
Цитата Сообщение от bedvit Посмотреть сообщение
Мне нужно запустить 8 потоков, выполнить, получить данные, еще раз запустить 8 потоков в другом методе и т.д. Привязать номер потока к задаче или еще как то оптимизировать очередь.
Задачи разные или одна и та же постоянно будет, только состояние будет меняться? Если вам только цикл распараллелить, то можете в сторону OMP глянуть...

Цитата Сообщение от bedvit Посмотреть сообщение
Мне нужно запустить 8 потоков, выполнить, получить данные, еще раз запустить 8 потоков в другом методе и т.д. Привязать номер потока к задаче или еще как то оптимизировать очередь
Пример с std::barrier, который, если не доступен, можете реализовать сами, наивно или скомуниздить готовое. Осторожно, там гомнокод, это только для демонстрации (если я правильно понял, что вы хотите).
Кликните здесь для просмотра всего текста
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
#include <iostream>
#include <barrier>
#include <thread>
#include <functional>
#include <cassert>
 
class thread_pool
{
public:
    thread_pool(unsigned n) : in(n), out(n, completion{this})
    {
        for (unsigned i = 1; i < n; ++i)
            pool.emplace_back([this, i]
                              { while (pass(i)); });
    }
 
    thread_pool(thread_pool const &) = delete;
    thread_pool &operator=(thread_pool const &) = delete;
 
    ~thread_pool()
    {
        assert(!task);
        pass(0);
        for (auto &t : pool)
            t.join();
    }
 
    // F = void(unsigned)
    template <class F>
    void parallel_launch(F &&f)
    {
        task = std::forward<F>(f);
        pass(0);
    }
 
private:
    bool pass(unsigned id)
    {
        in.arrive_and_wait();
        if (!task)
            return false;
        task(id);
        out.arrive_and_wait();
        return true;
    }
 
    struct completion
    {
        thread_pool *p;
        void operator()() const
        {
            p->task = nullptr;
        }
    };
 
    std::function<void(unsigned)> task;
    std::barrier<> in;
    std::barrier<completion> out;
    std::vector<std::thread> pool;
};
 
int main()
{
    constexpr unsigned n = 4;
    int arr[n] = {};
    auto print = [&arr]
    { for (auto x : arr) std::cout << x << ' '; std::cout << std::endl; };
    thread_pool p(n);
    p.parallel_launch([&arr](int id)
                      { ++arr[id]; });
    print();
    p.parallel_launch([&arr](int id)
                      { --arr[id]; });
    print();
}

https://wandbox.org/permlink/Df5WFlSEXPkG73l4
1
267 / 199 / 30
Регистрация: 26.11.2022
Сообщений: 859
03.05.2023, 01:38
смысл пула потоков ( threapool - как в названии темы ) в том что не тратится время на постоянно создание и слияние потоков. а в начале поздаётся нужное количество потоков - (обычно CoreCount-1) и они разбирают задания из очереди.

пул потоков может быть и с одним потоком.
0
 Аватар для bedvit
1208 / 259 / 22
Регистрация: 20.05.2016
Сообщений: 1,136
Записей в блоге: 21
03.05.2023, 09:56  [ТС]
zayats80888, выдает ошибку Visual Studio 2022 (С++20) Error C2338 static_assert failed: 'N4861 [thread.barrier.class]/5: is_nothrow_invocable_v<CompletionFunctio n&> shall be true'
Цитата Сообщение от zayats80888 Посмотреть сообщение
цикл распараллелить, то можете в сторону OMP глянуть...
В общем то да, но здесь возникаю накладные расходы на запуск потоков, с этим и должна справится threapool.

Aledveu, все верно, накладные расходы на создание потоков мы убрали, а на создание и поддержку очереди добавили. На малых данных, порядка 1000 элементов, использование threapool - увеличивает время выполнения, по сравнению с однопоточным вычислением. Моя цель убрать, по возможности, максимум накладных расходов из threapool.
0
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
03.05.2023, 10:16
Цитата Сообщение от bedvit Посмотреть сообщение
выдает ошибку Visual Studio 2022 (С++20) Error C2338 static_assert failed: 'N4861 [thread.barrier.class]/5: is_nothrow_invocable_v<CompletionFunctio n&> shall be true'
Чтоб скомпилировать, noexcept добавьте для оператора () у completion (по хорошему нужно это не только "заявить", но и гарантировать).

Цитата Сообщение от bedvit Посмотреть сообщение
В общем то да, но здесь возникаю накладные расходы на запуск потоков, с этим и должна справится threapool.
OMP поддерживает концепцию пула потоков, насколько я могу судить.
0
 Аватар для bedvit
1208 / 259 / 22
Регистрация: 20.05.2016
Сообщений: 1,136
Записей в блоге: 21
03.05.2023, 10:34  [ТС]
Цитата Сообщение от zayats80888 Посмотреть сообщение
Задачи разные или одна и та же постоянно будет,
Будет один и тот же цикл, с разными функциями (в разных методах класса), но всегда одинаковым количеством потоков (количество определяется в конструкторе класса)
C++
1
2
3
4
5
6
7
8
9
10
11
size_t dataCount = arrSize; //Количество данных для распараллеливания
size_t coresCount = this->coresCount;
std::vector<std::future<size_t >> thr(coresCount);
size_t part = dataCount / coresCount; //количество элементов для каждого потока
for (size_t treadN = 0; treadN < coresCount; treadN++) {
    size_t dataStart = treadN * part;//начало с 0 (включая 0)
    size_t dataEnd = (treadN + 1) * part - 1;//включая последний элемент
    if (treadN == coresCount - 1) { dataEnd = dataCount - 1; }
    thr[treadN] = this->pool->enqueue(Function1, treadN, dataStart, dataEnd, param1, param2, std::ref(param3));
    }//запускаем задания в поток
for (auto& th : thr) { th.get(); }//ждем все потоки
Поэтому, как таковая очередь не нужна, хотелось бы убрать накладные расходы на очередь.
Боюсь в OMP будет та же очередь.
Цитата Сообщение от zayats80888 Посмотреть сообщение
noexcept добавьте для оператора () у completion
да теперь все норм.
0
267 / 199 / 30
Регистрация: 26.11.2022
Сообщений: 859
03.05.2023, 10:55
Цитата Сообщение от bedvit Посмотреть сообщение
а на создание и поддержку очереди добавили
за всё надо платить. вы цифры приведите - чего вы добьётесь.

вот мой пример для задач с малым временем выполнения (5мс):


Кликните здесь для просмотра всего текста
[Info]: start WorkQueue_test
[Info]: Create Multithread Queue with NumThreades(7) and NumEntriesInQueue(10000) Result =1
[Info]: Create singlethread Queue with NumThreades(1) and NumEntriesInQueue(10000) Result =1
[Info]: Create nothread Queue with NumThreades(0) and NumEntriesInQueue(10000) Result =1
[Info]: Calibrating task time for 0.005000 seconds. Please wait ...
[Info]: Measured time: 0.004982 seconds with param(666859)
[Info]: Calculating TaskTime standart deviation. please wait...
[Info]: TaskTime Mean value: 0.004978 seconds
[Info]: TaskTime Standart deviation: 0.000075 seconds
[Info]: Running tests with num_tasks_in_queue=1000
[Info]: Multi Thread: Time 0.760664, for_one_task = 0.005325
[Info]: Single Thread: Time 4.960777, for one task = 0.004961
[Info]: No Thread: Time 4.932919, for one task = 0.004933


для задач которые требуют времени побольше
Кликните здесь для просмотра всего текста

[Info]: start WorkQueue_test
[Info]: Create Multithread Queue with NumThreades(7) and NumEntriesInQueue(10000) Result =1
[Info]: Create singlethread Queue with NumThreades(1) and NumEntriesInQueue(10000) Result =1
[Info]: Create nothread Queue with NumThreades(0) and NumEntriesInQueue(10000) Result =1
[Info]: Calibrating task time for 0.050000 seconds. Please wait ...
[Info]: Measured time: 0.050110 seconds with param(6739356)
[Info]: Calculating TaskTime standart deviation. please wait...
[Info]: TaskTime Mean value: 0.050026 seconds
[Info]: TaskTime Standart deviation: 0.000317 seconds
[Info]: Running tests with num_tasks_in_queue=1000
[Info]: Multi Thread: Time 7.751786, for_one_task = 0.054262
[Info]: Single Thread: Time 52.250195, for one task = 0.052250
[Info]: No Thread: Time 49.708642, for one task = 0.049709


поиграйтесь со своими задачами - померяйте накладные расходы
0
 Аватар для bedvit
1208 / 259 / 22
Регистрация: 20.05.2016
Сообщений: 1,136
Записей в блоге: 21
03.05.2023, 11:00  [ТС]
Aledveu, Вот тайминги нарезки строк, с длинной строки, количеством получаемых элементов и количеством итераций запуска метода класса
Кликните здесь для просмотра всего текста
Len(sTxt) = 13 888 895
Strings 1000000 Iterations 1
NO threads 8,203125E-02
std::thread: 0,03125
std::launch::async:0,03125
std::launch::deferred:0,0859375
ThreadPool:0,03125


Len(sTxt) = 1 288 894
Strings 100000 Iterations 10
NO threads 0,1367188
std::thread: 0,109375
std::launch::async:0,09375
std::launch::deferred:0,1367188
ThreadPool:9,765625E-02


Len(sTxt) = 118 893
Strings 10000 Iterations 100
NO threads 0,1054688
std::thread: 0,1992188
std::launch::async:8,203125E-02
std::launch::deferred:0,109375
ThreadPool:0,078125


Len(sTxt) = 10 892
Strings 1000 Iterations 1000
NO threads 0,1015625
std::thread: 1,175781
std::launch::async:0,109375
std::launch::deferred:0,1054688
ThreadPool:0,09375


Len(sTxt) = 991
Strings 100 Iterations 10000
NO threads 9,765625E-02
std::thread: 11,28125
std::launch::async:0,3164063
std::launch::deferred:0,125
ThreadPool:0,1914063


Len(sTxt) = 90
Strings 10 Iterations 100000
NO threads 0,1015625
std::thread: ---bad
std::launch::async:1,53125
std::launch::deferred:0,4140625
ThreadPool:0,8203125


Len(sTxt) = 8
Strings 1 Iterations 1000000
NO threads 0,3984375
std::thread: ---bad
std::launch::async:17,58203
std::launch::deferred:2,089844
ThreadPool:5,382813
0
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
03.05.2023, 11:01
Цитата Сообщение от bedvit Посмотреть сообщение
Будет один и тот же цикл, с разными функциями (в разных методах класса), но всегда одинаковым количеством потоков (количество определяется в конструкторе класса)
Я примерно так и понял. В контексте примера это будет выглядеть примерно так:
C++
1
2
3
4
5
6
7
8
p.parallel_launch([&](unsigned id)
                  {
                    size_t dataCount = arrSize; //Количество данных для распараллеливания
                    size_t part = dataCount / n; //количество элементов для каждого потока
                    size_t dataStart = id * part;//начало с 0 (включая 0)
                    size_t dataEnd = (id + 1) * part - 1;//включая последний элемент
                    if (id == n - 1) { dataEnd = dataCount - 1; }
                    Function1(id, dataStart, dataEnd, param1, param2, param3); });
1
267 / 199 / 30
Регистрация: 26.11.2022
Сообщений: 859
03.05.2023, 11:14
bedvit,
а не могли бы вы пояснить как из ваших таймингов получить накладные расходы?

Len(sTxt) = 10 892
Strings 1000 Iterations 1000
NO threads 0,1015625
std::thread: 1,175781
std::launch::async:0,109375
std::launch::deferred:0,1054688
ThreadPool:0,09375
получается что без потоков код быстрее чем в многопоточке?
NO threads 0,1015625
ThreadPool:0,09375
если я правильно понимаю что это время на одну задачу ?
0
 Аватар для bedvit
1208 / 259 / 22
Регистрация: 20.05.2016
Сообщений: 1,136
Записей в блоге: 21
03.05.2023, 11:24  [ТС]
Aledveu, на вашем скрине - да на 1000 запусков метода, за счет накладных расходов, многопоточные вычисления выполняются дольше. Это время на одну задачу, запущенную 1000 раз.
Другими словами, когда у нас много данных и одна итерация, многопоточный алгоритм быстр и вне конкуренции.
Когда данных мало, для усреднения результата, я запускаю в цикле (количество итераций) тот же метод, и тогда видим, что от 1000 и менее элементов в массиве для распараллеливания - многопоточные алгоритмы начинаю проигрывать однопоточному, за счет накладных расходов. Причем не равномерно, больше всего проигрывает std::thread, потом std::async с ключом std::launch::async, потом ThreadPool, и уже потом std::async с ключом std::launch::deferred (видимо потому как по факту это один поток)
0
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
03.05.2023, 11:33
Цитата Сообщение от bedvit Посмотреть сообщение
Когда данных мало, для усреднения результата, я запускаю в цикле (количество итераций) тот же метод, и тогда видим, что от 1000 и менее элементов в массиве для распараллеливания многопоточные алгоритмы начинаю проигрывать однопоточному, за счет накладных расходов
Избавиться совсем от накладных расходов не получится, синхронизация дело затратное. "Золотой пули" вы не найдете. Распараллеливание нужно применять там, где оно действительно необходимо и распределять задачи нужно исходя не из числа потоков, а исходя из минимальной загрузки одного потока, т.е. если сумарно работы на образно два потока, то не надо её распихивать на восемь.
0
 Аватар для bedvit
1208 / 259 / 22
Регистрация: 20.05.2016
Сообщений: 1,136
Записей в блоге: 21
03.05.2023, 11:46  [ТС]
Цитата Сообщение от zayats80888 Посмотреть сообщение
синхронизация дело затратное.
мне как таковая не нужна синхронизация, нужен старт и функция обратного вызова, говорящая данные есть смотри поток ( а может и так, задача в потоке завершёна, всё. Данные я увижу в итогах сам). Данные в потоках и сами потоки не зависят от вычислений другого потока. И запуск следующих задач будет только после того как пул из, к примеру, 8 потоков будет завершен. т.е. нужно сделать максимально просто. затраты только на загрузку задачи в поток (запуск потока еще в конструкторе был) и на получение отсечки, что все потоки посчитались, ставим на ожидание потоки. Какие здесь возможны затраты на синхронизацию?
0
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
03.05.2023, 12:00
Цитата Сообщение от bedvit Посмотреть сообщение
мне как таковая не нужна синхронизация, нужен старт и функция обратного вызова, говорящая данные есть смотри поток.
Это и есть синхронизация, как минимум две точки синхронизации:
1) положить данные в "общую карзину", сделать доступными для потоков и начать работу
2) забрать результат

Если два пункта затрачивают время, сопостовимое с временем собственно полезной работы, то распараллеливание теряет эффективность.

Добавлено через 10 минут
В частности, разбить строку длиной 90 на 9 строк длиной 10 будет быстрее, чем два пункта выше + вырезать из той же строки 1 строку, как бы вы не реализовали эти два пункта. Поэтому эту операцию нет смысла распараллеливать.
0
 Аватар для bedvit
1208 / 259 / 22
Регистрация: 20.05.2016
Сообщений: 1,136
Записей в блоге: 21
03.05.2023, 12:33  [ТС]
Добавил в Тайминги parallel_launch - смотрится вполне неплохо, правда при запуске деструктора ошибка есть, пока не смотрел в чем дело.
Кликните здесь для просмотра всего текста
Len(sTxt) = 13 888 895
Strings 1000000 Iterations 1
NO threads 0,09375
std::thread: 3,515625E-02
std::launch::async:0,03125
std::launch::deferred:9,765625E-02
ThreadPool:0,03125
parallel_launch:0,03125

Len(sTxt) = 1 288 894
Strings 100000 Iterations 10
NO threads 0,2265625
std::thread: 0,1953125
std::launch::async:0,1796875
std::launch::deferred:0,2226563
ThreadPool:0,1835938
parallel_launch:0,1796875

Len(sTxt) = 118 893
Strings 10000 Iterations 100
NO threads 0,1132813
std::thread: 0,2148438
std::launch::async:0,0859375
std::launch::deferred:0,1171875
ThreadPool:0,0859375
parallel_launch:0,0859375

Len(sTxt) = 10 892
Strings 1000 Iterations 1000
NO threads 9,765625E-02
std::thread: 1,183594
std::launch::async:9,765625E-02
std::launch::deferred:0,1054688
ThreadPool:8,984375E-02
parallel_launch:0,1132813

Len(sTxt) = 991
Strings 100 Iterations 10000
NO threads 0,1015625
std::thread: 11,29688
std::launch::async:0,3125
std::launch::deferred:0,125
ThreadPool:0,1757813
parallel_launch:0,1445313

Len(sTxt) = 90
Strings 10 Iterations 100000
NO threads 0,1054688
std::thread: ---bad
std::launch::async:1,496094
std::launch::deferred:0,359375
ThreadPool:0,8359375
parallel_launch:0,2617188

Цитата Сообщение от zayats80888 Посмотреть сообщение
положить данные в "общую карзину"
Этого не нужно, данные и так лежат в общей корзине (Сишный массив)
Цитата Сообщение от zayats80888 Посмотреть сообщение
забрать результат
забирать не нужно, тот же массив.
Я так понимаю, есть расходы разморозить поток-запустить задачу, получить отметку, что задача завершилась, заморозить поток.
Цитата Сообщение от zayats80888 Посмотреть сообщение
а исходя из минимальной загрузки одного потока
- это не тривиальная задача, и я не знаю как её решить. Разные функции - имеют разные алгоритмы, разные ПК могут иметь разную пропускную шину, память, разные кеши ЦП и т.д. Это только тест каждого ПК, но это не поможет настроить общую схему.
0
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
03.05.2023, 12:45
Цитата Сообщение от bedvit Посмотреть сообщение
смотрится вполне неплохо
Не вижу существенного выигрыша, все в пределах погрешности, имхо.
Цитата Сообщение от bedvit Посмотреть сообщение
Я так понимаю, есть расходы разморозить поток, получить отметку, что задача завершилась, заморозить поток.
Конечно.
Цитата Сообщение от bedvit Посмотреть сообщение
это не тривиальная задача, и я не знаю как её решить. Разные ПК могут иметь разную пропускную шину, память, разные кеши ЦП и т.д. Это только тест каждого ПК, но это не поможет настроить общую схему.
Почему же, судя по вашим замерам, распараллеливать имеет смысл начиная с
Цитата Сообщение от bedvit Посмотреть сообщение
Len(sTxt) = 118 893
Strings 10000 Iterations 100
не раньше. Вот и прикиньте примерный объем работы для одного потока.
0
267 / 199 / 30
Регистрация: 26.11.2022
Сообщений: 859
03.05.2023, 12:53
может сначала критерии написать - типа есть задача на которую тратится столько-то времени - это может быть и функция от объема данных.
Есть вариант её разбить и запустить в один поток или несколько - и посчитать выигрыш

пока что действительно непонятно что выхотите добиться распараллеливанием и в каком случае это надо.

а уже потом оптимизировать
0
 Аватар для bedvit
1208 / 259 / 22
Регистрация: 20.05.2016
Сообщений: 1,136
Записей в блоге: 21
03.05.2023, 14:29  [ТС]
Отклонения от однопоточного алгоритма начинается от 1 тыс. строк (в моем тесте, см. спойлер)
parallel_launch на малых данных до 2х раз быстрее ThreadPool и всего в 2 раза медленнее 1 потока (std::thread на этих данных просто уходил в минуты)
Возможно ли еще оптимизировать parallel_launch?

Кликните здесь для просмотра всего текста
Strings 1000 Iterations 1000
NO threads 0,1015625
std::thread: 1,269531
std::launch::async:0,1171875
std::launch::deferred:0,109375
ThreadPool:9,765625E-02
parallel_launch:0,09375

Strings 500 Iterations 2000
NO threads 0,1015625
std::thread: 2,421875
std::launch::async:0,1328125
std::launch::deferred:0,1054688
ThreadPool:0,1132813
parallel_launch:0,1015625

Strings 250 Iterations 4000
NO threads 9,765625E-02
std::thread: 4,640625
std::launch::async:0,1796875
std::launch::deferred:0,109375
ThreadPool:0,1289063
parallel_launch:0,109375

Strings 125 Iterations 8000
NO threads 0,1015625
std::thread: 9,222656
std::launch::async:0,2578125
std::launch::deferred:0,125
ThreadPool:0,1679688
parallel_launch:0,1328125

Strings 62 Iterations 16129
NO threads 9,765625E-02
std::thread: ---bad
std::launch::async:0,4140625
std::launch::deferred:0,1445313
ThreadPool:0,2304688
parallel_launch:0,1914063

Strings 31 Iterations 32258
NO threads 0,1015625
std::thread: ---bad
std::launch::async:0,609375
std::launch::deferred:0,1875
ThreadPool:0,3007813
parallel_launch:0,1445313

Strings 15 Iterations 66666
NO threads 0,1054688
std::thread: ---bad
std::launch::async:1,058594
std::launch::deferred:0,28125
ThreadPool:0,421875
parallel_launch:0,1992188

Цитата Сообщение от Aledveu Посмотреть сообщение
непонятно что выхотите добиться распараллеливанием
Сделать максимально быстрым операции распараллеливания для моей задачи, когда не нужны очереди, синхронизация между потоками, синхронизации очереди задач и т.д. т.е. минимально простой алгоритм: Загрузить в поток функцию, получить отметку, что функция отработала, заморозить поток до следующей функции/задачи (количество потоков всегда фиксированное число).
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
03.05.2023, 14:29
Помогаю со студенческими работами здесь

ThreadPool и использование параллельных классов: распределение потоков по ядрам ЦП
задаю в переменную кол-во потоков и мне надо чтобы каждый поток выполнялся на ядре. Например 2х ядерный процессор. Задаю 4 потока и 2...

Обработка элементов в несколько потоков: ThreadPool или еще варианты?
Во общем дело такое: Есть listview в нем N итемов, мне нужно пройтись по каждому взять данные каждого итема и записать их в файл, и хочу...

Смысл значений ThreadPool.SetMaxThreads и ThreadPool.SetMinThreads
Товарищи объясните пожалуйста из каких соображений назначать значения ThreadPool.SetMaxThreads и ThreadPool.SetMinThreads

Как оптимизировать перемножние результатов массива задач?
Привет всем! Задача следующая: имею массив - Task&lt;BigInteger&gt; нужно перемножить все результаты. На данный момент это решается...

Алгоритм оптимального распараллеливания задач на несколько потоков
Имеем 4-ядерный процессор и 100 задач. Задачи разные по сложности - могут выполняться от 1 до 10 секунд каждая. Необходимо равномерно...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
Фото: Daniel Greenwood
kumehtar 13.11.2025
Расскажи мне о Мире, бродяга
kumehtar 12.11.2025
— Расскажи мне о Мире, бродяга, Ты же видел моря и метели. Как сменялись короны и стяги, Как эпохи стрелою летели. - Этот мир — это крылья и горы, Снег и пламя, любовь и тревоги, И бескрайние. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru