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

Уменьшить нагрузку потока - C++

Восстановить пароль Регистрация
 
DrobyshevAlex
1164 / 1114 / 16
Регистрация: 31.05.2012
Сообщений: 3,059
09.06.2012, 23:14     Уменьшить нагрузку потока #1
Делаю многопоточный сервер.
Клиенты подключаются, парсится команда и дальше она отдаётся в очередь.

Создаётся несокль потоков. Все висят на семафоре. Как только добавилась команда, добаляется симафор, и какой то из потоков забирает из очереди класс клиента.
В нём вызывается функция Update.
Так как это ФТП сервер, и может передаваться файл, я сделал отправку и приём частами, на данный момент по 1024 байта.
То есть отдаю 1024 байта или принимаю, и если операция не закончена, то функция Update возвращает false и поток опять становится в очередь. Семафор опять увеличивается на 1.
Дальше опять какой то поток берёт клиента и опять всё по кругу.

Так вот, когда идёт приём или передача файла, получается что приложение начинает тратить 99ю9 процента процессора.
И если в этот момент пытаться вторым соеденением пользоваться - всё очень сильно тормозит...

Вот функция которая крутится в отдельном потоке.
C++
1
2
3
4
5
6
7
8
9
10
11
void FTPThread::Update()
{
    sem_wait(&FTP->sem);
    //Log->Print(LOG_DEBUG, "FTPThread::Update()");
    
    int sock = FTP->getNextQueue();
    FTPSession * ses = FTP->getSession(sock);
    
    if (ses != NULL && ses->Update())
        FTP->addQueue(sock);
}
Вот добавление и удаление в очередь клиентов
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void FTPManager::addQueue(int sock)
{
    //Log->Print(LOG_DEBUG, "FTPManager::addDataQueue");
    queue.push(sock);
    sem_post(&FTP->sem);
}
 
int FTPManager::getNextQueue()
{
    //Log->Print(LOG_DEBUG, "FTPManager::getNextData");
    Lock();
    int sock = 0;
    if (!queue.empty())
    {
        sock = queue.front();
        queue.pop();
    }
    UnLock();
    return sock;
}
Тут выполняется команда клиента за 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
bool FTPSession::Update()
{
    if (!commands.empty())
    {
        Command * c = commands.front();
        commands.pop();
        if (Handler * h = FTPProtocol::getCommands(c->command.c_str()))
        {
            if (h->flag == 0 || isAuth())
            {
                (*this.*h->handler)(c);
            }
            else
            {
                if (Reply * reply = FTPProtocol::getReply(FTPProtocol::ACCESS_DENIED))
                {
                    send(reply->reply);
                }
            }
        }
    }
    return !data_session->Update();
}
 
bool DataSession::Update()
{
    //Log->Print(LOG_DEBUG, "DataSession::Update");
    
    if (!commands.empty())
    {
        Command * c = commands.front();
        if (c->command == "LIST")
        {
            if (sendList())
            {
                commands.pop();
            }
        }
        else if (c->command == "STOR")
        {
            if ((isConnected() || fp != NULL) && storFile(c))
            {
                Log->Print(LOG_DEBUG, "DataSession::STOR END");
                commands.pop();
            }
        }
        
        else if (isConnected() && c->command == "RETR")
        {
            if (retrFile(c))
            {
                commands.pop();
            }
        }
    }
 
    return commands.empty();
}
То есть когда клиент подключен, но нет команд не выполненых, тогда всё отлично, а вот когда выполняется команда, всё ужасно виснит.
Как можно исправить ситуацию?)
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
09.06.2012, 23:14     Уменьшить нагрузку потока
Посмотрите здесь:

C++ Уменьшить последовательность
Создание потока из потока. C++
Как уменьшить чувствительность мыши? C++
Уменьшить все элементы массива на 20 C++
Как уменьшить количество кода? C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Ksan
26 / 26 / 0
Регистрация: 02.11.2010
Сообщений: 370
09.06.2012, 23:16     Уменьшить нагрузку потока #2
можно раз в цикл Sleep(1); но это замедлит выполнение. а можно раз в несколько циклов. тогда ему будет легче
DrobyshevAlex
1164 / 1114 / 16
Регистрация: 31.05.2012
Сообщений: 3,059
09.06.2012, 23:30  [ТС]     Уменьшить нагрузку потока #3
поправка, виснит именно на функции передачи файла на сервер При скачки нагрузка 2-3 процента.

То есть там пока идёт передача, выполнятеся в функции
C++
1
2
3
4
if (isConnected())
    {
        return false;
    }
а другой поток, где сами сокеты опрашиваются, пишет в файл
C++
1
2
3
4
5
6
7
void DataSession::appendData(char* b, int len)
{
    //Log->Print(LOG_DEBUG, "DataSession::appendData");
    fwrite(b, 1,len, fp);
    file_hash.update(b, len);
    file_size += len;
}
Получается что когда весь файл будет передан, произойдёт дисконнект, и тогда поток этот выполнит действия (закроет файл, сохранит данный в бд) и завершится. А поки идёт приём файла, он просто грузит систему...

Добавлено через 1 минуту
Цитата Сообщение от Ksan Посмотреть сообщение
можно раз в цикл Sleep(1);
Ну циклов всего 4, если каждый раз по секунде спать, то при 40 подключенных клиентах по фтп, по 10 клиентов на поток, клиент будет обрабатывать раз в 10 секунд
Bers
Заблокирован
09.06.2012, 23:37     Уменьшить нагрузку потока #4
По Миллисекунде. (на самом деле может быть и подольше).
Sleep кушает миллисекунды. 1000 миллисекунд - 1 секунда.
4 миллисекунды - вечность для процессора, и слишком мало, что бы ты успел моргнуть.
DrobyshevAlex
1164 / 1114 / 16
Регистрация: 31.05.2012
Сообщений: 3,059
09.06.2012, 23:42  [ТС]     Уменьшить нагрузку потока #5
Я не уточнил, это под линукс, там spleep по секунде, я проверял. Сделал через нанослипп, помогло
Но видимо нужно пересмотреть структуру приложения, так как получается что мы один поток опросту гоняем, пока он мог что то обрабатывать
Bers
Заблокирован
10.06.2012, 00:29     Уменьшить нагрузку потока #6
Цитата Сообщение от DrobyshevAlex Посмотреть сообщение
Я не уточнил, это под линукс, там spleep по секунде, я проверял. Сделал через нанослипп, помогло
Но видимо нужно пересмотреть структуру приложения, так как получается что мы один поток опросту гоняем, пока он мог что то обрабатывать
Мы на работе используем кросс-платформенное решение. Не могу светить код.
Но думаю, если опишу одну лишь идею, то беды не будет:


Смысл такой: препроцессор определяет где мы хотим взлететь:

1. Линукс: см в сторону gettimeofday()

2. Виндовс: см в сторону QueryPerformanceCounter(), QueryPerformanceFrequency()
(Так же, важно учитывать количество ядрышек, кои участвуют в процессе, ибо под виндовс на много-ядерных могут быть перекосы. Лучше настроить функции на работу с одним ядрышком, а потом восстановить штатную работу)

Таким образом мы засекаем время.

Далее, немножко поспим (ну или множко, это уж как нам захочется):

1. Линукс: usleep(микросенунды) поспать немножко. 10 микросекунд хватит за глаза что бы разгрузить ЦП

2. Виндовс: Если пауза меньше 1000, спим одну милисекунду, иначе - спим val милисекунд/1000

Итого: получаем две функции. Первая засекает время с точностью до микросекунд. Вторая организует задержку в микросекундах.

Профит: единообразная работа под линукс и виндовс. Временные задержки измеряемые в микросекундах. 1 секунда = 1 000 000 микросекунд.
DrobyshevAlex
1164 / 1114 / 16
Регистрация: 31.05.2012
Сообщений: 3,059
10.06.2012, 00:34  [ТС]     Уменьшить нагрузку потока #7
Ну у меня код на epoll, он не то что под виндовс, он под freebds не заработает
Так что думаю пока остановлюсь на одной функции, nanosleep.
Но всё равно хотелось бы избавиться от слипов вообще.

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

Вот только в архитектуру пока это не вписывается) Либо нужно переделать что то либо костылями прукручивать
Bers
Заблокирован
10.06.2012, 00:42     Уменьшить нагрузку потока #8
ну хз, тут нужно втыкать в ситуацию)) Но пахнет "событийной моделью".
То бишь, циклы дочек не крутятся, пока нечто их не запустит. Нечто должно пырять очень быстро, переодически толкая то, или иное. А все остальное время спать.
Совсем от слипов все равно не получится избавиться.

В винде есть ещё вариант - выставлять кванты времени процессу. Тобишь, можно выставить такой режим, что он будет шуршать на низком приоритете, в фоновом режиме, и не мешать всем остальным. Тогда у него можно крутить циклы без всяких слипов. Он все равно не будет нагружать процессор. Наверняка, нечто подобное присутствует в апи других осей.
novi4ok
549 / 502 / 8
Регистрация: 23.07.2009
Сообщений: 2,359
Записей в блоге: 1
10.06.2012, 00:50     Уменьшить нагрузку потока #9
а никакого трассирования не предусмотрено? такие вещи без него вообще сложно отлаживать. встрой трассирование (отключаемое), и сходу увидишь, где твоя штучка циклит понапрасну.
Avazart
 Аватар для Avazart
6904 / 5144 / 253
Регистрация: 10.12.2010
Сообщений: 22,621
Записей в блоге: 17
10.06.2012, 01:27     Уменьшить нагрузку потока #10
Уменьшить нагрузку потока
- понизить приоритет потока
DrobyshevAlex
1164 / 1114 / 16
Регистрация: 31.05.2012
Сообщений: 3,059
10.06.2012, 02:39  [ТС]     Уменьшить нагрузку потока #11
Цитата Сообщение от novi4ok Посмотреть сообщение
а никакого трассирования не предусмотрено? такие вещи без него вообще сложно отлаживать. встрой трассирование (отключаемое), и сходу увидишь, где твоя штучка циклит понапрасну.
Я и так нешел где цикл. Просто он не совсем по напрасну, с мента прихода команды на приём файла и до момента пока сокет примит весь файл - крутится цикл пустой.
Вот я и думаю как от этого избавится. Просто в конце приёма не чего клиент не присылает а просто отключается. У меня в цикле и идёт проверка пока не отключится.


Цитата Сообщение от Avazart Посмотреть сообщение
- понизить приоритет потока
Я просто на пхп пишу обычно, и мало знаком с с++ Погуглю на эту тему
novi4ok
549 / 502 / 8
Регистрация: 23.07.2009
Сообщений: 2,359
Записей в блоге: 1
10.06.2012, 03:11     Уменьшить нагрузку потока #12
Цитата Сообщение от DrobyshevAlex Посмотреть сообщение
Я и так нешел где цикл. Просто он не совсем по напрасну, с мента прихода команды на приём файла и до момента пока сокет примит весь файл - крутится цикл пустой.
Вот я и думаю как от этого избавится. Просто в конце приёма не чего клиент не присылает а просто отключается. У меня в цикле и идёт проверка пока не отключится.
архитектурка дерьмовенькая. такие вещи ловятся по событию, а не поллингом.
DrobyshevAlex
1164 / 1114 / 16
Регистрация: 31.05.2012
Сообщений: 3,059
10.06.2012, 04:13  [ТС]     Уменьшить нагрузку потока #13
Так вот именно что всё по событиям и ловится. И для всех команд подходит. И сюда бы подошло возможно. Но из за того, что чтение сокетов идёт в одном потоке, а всё остальное в другом, получается что когда чтение с сокета идёт - потоку обрабатывать нечего. Я и говорю что придётся переделывать работу приложения...
Ksan
26 / 26 / 0
Регистрация: 02.11.2010
Сообщений: 370
10.06.2012, 11:33     Уменьшить нагрузку потока #14
Bers, как спать микросекунду? Виндосовские функции Sleep(), SDL_Delay и тп только в милли принимают
Bers
Заблокирован
10.06.2012, 13:58     Уменьшить нагрузку потока #15
Цитата Сообщение от Ksan Посмотреть сообщение
Bers, как спать микросекунду? Виндосовские функции Sleep(), SDL_Delay и тп только в милли принимают
Дергаешь не Sleep(милисек), а некий Delay(микросекунды), который внутри себя сам разберётся, под линукс ты, или под виндой. Если под виндой сделает: Sleep(микросекунды/1000), для любого аргумента микросек меньше 1000.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
10.06.2012, 14:08     Уменьшить нагрузку потока
Еще ссылки по теме:

C++ Вызывть метод одного потока из другого потока
C++ Все элементы массива уменьшить на 20
Как уменьшить нагрузку ЦП, в SFML? C++

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

Или воспользуйтесь поиском по форуму:
taras atavin
Ушёл с форума.
 Аватар для taras atavin
3569 / 1752 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
10.06.2012, 14:08     Уменьшить нагрузку потока #16
DrobyshevAlex, а зачем такая маета? Узкая то здесь магистраль, а не камень.
Yandex
Объявления
10.06.2012, 14:08     Уменьшить нагрузку потока
Ответ Создать тему
Опции темы

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