Есть udp сервер, работает в виде (допустим) 4-х потоков, открытых в начале программы, один из них сокет который на каждый приём пакета передаёт данные в очередь из которой эту задачу забирают оставшиеся, с помощью pthread_cond...
Посылаю пачку из 100 запросов, первые три таких пачки проходят нормально, четвёртая, проходит с нереальными тормозами, все пачки запросов абсолютно одинаковые, смотрел в логах нигде нет не одного вызова lock уже залоченого мьютекса (он один), для pthread_cond.
Идеи есть поставь маленькую паузу в каждом
потоке (чувствую, они у тебя циклически работают ).
Посмотришь на результат. (Вместо паузы можно также
sched_yield вызвать).
Здравствуйте, kiamor, Вы писали:
K>Здравствуйте, naje.
N>>Есть какие-то идеи?
K>Идеи есть поставь маленькую паузу в каждом K>потоке (чувствую, они у тебя циклически работают ). K>Посмотришь на результат. (Вместо паузы можно также K>sched_yield вызвать).
А что значит циклически? Я заметил что они почему-то переключатся начинают как-то неправельно, т.б. слишком часто и в топе после того как всё отработалось этот процес ещё долго висит, я так понимаю это шедулер продолжает что-то делать. Один запрос выполняется в юзерспейсе где-то сотую секунды, полностью запрос с учётом запросов к базе где-то 3 десятые секунды, с учётом того что в юзерспейсе процесс выполняется мало получается что если запустить 10 потоков то 10 запросов будет выполнятся тоже приблизительно 3 десятые секунды, и это на практике работает, и для 20 и 30 потоков, т.б. 30 запросов за 3 десятые секунды, но потом что-то происходит, и какая-то след. пачка, выполняется медленнее чем если бы всё это обслуживал один поток (на один запрос бывает до секунды на 10 до 10 секунд), единственная синхронизация между потоками это pthread_cond.. с мьютексом, для обработки очереди запросов, больше не нужно. Если ставить sched_yield, то где? Там где ставятся задания в очередь или там где забираются?
Циклически — значит периодически
Ну не один же раз поток вызывается. Я так понял, ты организовал
что-то вроде пула потоков, которым и пользуешься.
Теперича про sched_yield. Куда ее воткнуть — тебе виднее. Тут я,
как гритца, бессилен. Если код потока представляет собой цикл —
влепи в конец. Если код потока выполняется сначала до конца при
каждом обращении к потоку — тоже можешь влепить в конец. Однако
здесь прикинь время выполнения. Может и в середину неплохо будет.
Зачем ваще нужна ента самая фигня. Задержка, либо sched_yield,
нужна для того, чтобы пнуть планировщик и заставить его работать.
Надеюсь тебе известно, что из себя представляет библиотека pthread?
Та еще штучка. Этот самый бантик в сочетании с определенными задачами
поворачивается к программеру Ж. (Именно с большой буквы). Я с коллегами
наткнулся на один из таких приколов. Наш код вел себя так, как будто
линух вообще система с невытесняющей многозадачностью. Мы просто охренели.
Хотя казалось бы, пара процессов, в каждом по нескольку потоков. Ничего
страшного на первый взгляд не было. Единственное что спасло — периодический
пинок планировщику в коде каждого потока.
Здравствуйте, kiamor, Вы писали:
K>Здравствуйте, naje.
K>Циклически — значит периодически K>Ну не один же раз поток вызывается. Я так понял, ты организовал K>что-то вроде пула потоков, которым и пользуешься.
K>Теперича про sched_yield. Куда ее воткнуть — тебе виднее. Тут я, K>как гритца, бессилен. Если код потока представляет собой цикл - K>влепи в конец. Если код потока выполняется сначала до конца при K>каждом обращении к потоку — тоже можешь влепить в конец. Однако K>здесь прикинь время выполнения. Может и в середину неплохо будет.
K>Зачем ваще нужна ента самая фигня. Задержка, либо sched_yield, K>нужна для того, чтобы пнуть планировщик и заставить его работать. K>Надеюсь тебе известно, что из себя представляет библиотека pthread? K>Та еще штучка. Этот самый бантик в сочетании с определенными задачами K>поворачивается к программеру Ж. (Именно с большой буквы).
Не помогло, похоже что Ж, начинаю переделывать в несколько процесов.
Re[5]: проблема с pthread
От:
Аноним
Дата:
09.09.03 13:23
Оценка:
Здравствуйте, naje, Вы писали:
N>Здравствуйте, kiamor, Вы писали:
K>>Здравствуйте, naje.
K>>Циклически — значит периодически K>>Ну не один же раз поток вызывается. Я так понял, ты организовал K>>что-то вроде пула потоков, которым и пользуешься.
K>>Теперича про sched_yield. Куда ее воткнуть — тебе виднее. Тут я, K>>как гритца, бессилен. Если код потока представляет собой цикл - K>>влепи в конец. Если код потока выполняется сначала до конца при K>>каждом обращении к потоку — тоже можешь влепить в конец. Однако K>>здесь прикинь время выполнения. Может и в середину неплохо будет.
K>>Зачем ваще нужна ента самая фигня. Задержка, либо sched_yield, K>>нужна для того, чтобы пнуть планировщик и заставить его работать. K>>Надеюсь тебе известно, что из себя представляет библиотека pthread? K>>Та еще штучка. Этот самый бантик в сочетании с определенными задачами K>>поворачивается к программеру Ж. (Именно с большой буквы).
IMHO sched_yield здесь не нужен — в idle time рабочие потоки должны висеть в wait() на pthread_cond,
а принимающий запросы поток на receive(), никаких циклов быть не должно.
N>Не помогло, похоже что Ж, начинаю переделывать в несколько процесов.
Ну зачем же так сразу сдаваться, или очень срочно надо сделать?
Посмотрел бы, какая загрузка проца, когда начинаются тормоза.
Если 100%, то кто её устраивает. Может БД решила заняться какими-то своими делами?
Если 0%, то в каком состоянии висит твой процесс и его thread'ы в это время.
Попробуй выводить в файл id thread'ов и время прохождения ими определённых точек и т.п.
А что будет, если запустить только 2 thread'а?
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, naje, Вы писали:
N>>Здравствуйте, kiamor, Вы писали:
K>>>Здравствуйте, naje.
K>>>Циклически — значит периодически K>>>Ну не один же раз поток вызывается. Я так понял, ты организовал K>>>что-то вроде пула потоков, которым и пользуешься.
K>>>Теперича про sched_yield. Куда ее воткнуть — тебе виднее. Тут я, K>>>как гритца, бессилен. Если код потока представляет собой цикл - K>>>влепи в конец. Если код потока выполняется сначала до конца при K>>>каждом обращении к потоку — тоже можешь влепить в конец. Однако K>>>здесь прикинь время выполнения. Может и в середину неплохо будет.
K>>>Зачем ваще нужна ента самая фигня. Задержка, либо sched_yield, K>>>нужна для того, чтобы пнуть планировщик и заставить его работать. K>>>Надеюсь тебе известно, что из себя представляет библиотека pthread? K>>>Та еще штучка. Этот самый бантик в сочетании с определенными задачами K>>>поворачивается к программеру Ж. (Именно с большой буквы).
А>IMHO sched_yield здесь не нужен — в idle time рабочие потоки должны висеть в wait() на pthread_cond, А>а принимающий запросы поток на receive(), никаких циклов быть не должно.
Отож, но в топе когда запросы прошли показывает что что-то ещё работает, причём конкретно работает.
N>>Не помогло, похоже что Ж, начинаю переделывать в несколько процесов.
А>Ну зачем же так сразу сдаваться, или очень срочно надо сделать? А>Посмотрел бы, какая загрузка проца, когда начинаются тормоза. А>Если 100%, то кто её устраивает. Может БД решила заняться какими-то своими делами? А>Если 0%, то в каком состоянии висит твой процесс и его thread'ы в это время. А>Попробуй выводить в файл id thread'ов и время прохождения ими определённых точек и т.п. А>А что будет, если запустить только 2 thread'а?
Надо быстро сделать, но и разобратся очень сильно хочется.
С загрузкой всё нормально, никто ничево не делает.
Re[7]: проблема с pthread
От:
Аноним
Дата:
09.09.03 15:20
Оценка:
Здравствуйте, naje, Вы писали:
N>Здравствуйте, Аноним, Вы писали:
А>>Здравствуйте, naje, Вы писали:
N>>>Здравствуйте, kiamor, Вы писали:
K>>>>Здравствуйте, naje.
K>>>>Циклически — значит периодически K>>>>Ну не один же раз поток вызывается. Я так понял, ты организовал K>>>>что-то вроде пула потоков, которым и пользуешься.
K>>>>Теперича про sched_yield. Куда ее воткнуть — тебе виднее. Тут я, K>>>>как гритца, бессилен. Если код потока представляет собой цикл - K>>>>влепи в конец. Если код потока выполняется сначала до конца при K>>>>каждом обращении к потоку — тоже можешь влепить в конец. Однако K>>>>здесь прикинь время выполнения. Может и в середину неплохо будет.
K>>>>Зачем ваще нужна ента самая фигня. Задержка, либо sched_yield, K>>>>нужна для того, чтобы пнуть планировщик и заставить его работать. K>>>>Надеюсь тебе известно, что из себя представляет библиотека pthread? K>>>>Та еще штучка. Этот самый бантик в сочетании с определенными задачами K>>>>поворачивается к программеру Ж. (Именно с большой буквы).
А>>IMHO sched_yield здесь не нужен — в idle time рабочие потоки должны висеть в wait() на pthread_cond, А>>а принимающий запросы поток на receive(), никаких циклов быть не должно.
Предыдущий советчик имел ввиду, что в idle time, когда тебе делать нечего, ты бегаешь по циклу и кушаешь время (в том числе и то, которое могло бы достаться твоему другому thread'у, которому есть, что делать).
N>Отож, но в топе когда запросы прошли показывает что что-то ещё работает, причём конкретно работает.
Ну если ты не знаешь, кто, откуда же я знаю.
N>>>Не помогло, похоже что Ж, начинаю переделывать в несколько процесов.
А>>Ну зачем же так сразу сдаваться, или очень срочно надо сделать? А>>Посмотрел бы, какая загрузка проца, когда начинаются тормоза. А>>Если 100%, то кто её устраивает. Может БД решила заняться какими-то своими делами? А>>Если 0%, то в каком состоянии висит твой процесс и его thread'ы в это время. А>>Попробуй выводить в файл id thread'ов и время прохождения ими определённых точек и т.п. А>>А что будет, если запустить только 2 thread'а?
N>Надо быстро сделать, но и разобратся очень сильно хочется. N>С загрузкой всё нормально, никто ничево не делает.
тогда в каком состоянии висят thread'ы?
man ps, определить, висят они на mutex'е или на I/O точно можно.
можно в этот момент в наглую взять и приатачиться к процессу, поглядеть стек у thread'ов — в каком месте они висят.
// за правильность не ручаюсь, но идея, я думаю, ясна
#define TRACE printf("%u %ld %s:%u\n", get_thread_id(), time(NULL), __FILE__, __LINE__);
И расставляем эту радасть по файлам — до и после запросов к БД, до и после receive, pthread_cond_wait или как там её.
Время, конечно, лучше выбрать более точное, чем time(), но 10 секунд и так можно заметить.
Здравствуйте, Аноним, Вы писали:
А>>>IMHO sched_yield здесь не нужен — в idle time рабочие потоки должны висеть в wait() на pthread_cond, А>>>а принимающий запросы поток на receive(), никаких циклов быть не должно.
Ну и я ж про это, + те потоки которые в данный момент посылают к базе запросы тоже должны висеть на recv. Так и есть при первых пачках, т.б. когда запрос посылает один из потоков второй что-то делает. И т.д. блокировки во время выполнения запросов нет никакой (это по контрольным печатям).
N>>Отож, но в топе когда запросы прошли показывает что что-то ещё работает, причём конкретно работает.
А>Ну если ты не знаешь, кто, откуда же я знаю.
Вот в том то и дело что все потоки остоновились кто на cond_wait, кто на recv, а в это время почему то в топе что-то. И у меня только один подозреваемый — это шедулер.
А>тогда в каком состоянии висят thread'ы? А>man ps, определить, висят они на mutex'е или на I/O точно можно.
У меня стандартная реализация FreeBSD там всё в юзер спейсе, ps ничево не даст.
А>можно в этот момент в наглую взять и приатачиться к процессу, поглядеть стек у thread'ов — в каком месте они висят.
А>// за правильность не ручаюсь, но идея, я думаю, ясна А>#define TRACE printf("%u %ld %s:%u\n", get_thread_id(), time(NULL), __FILE__, __LINE__);
А>И расставляем эту радасть по файлам — до и после запросов к БД, до и после receive, pthread_cond_wait или как там её. А>Время, конечно, лучше выбрать более точное, чем time(), но 10 секунд и так можно заметить.
Это всё делел, получил результаты которые выше вкратце описал. Единственное подозрительное заметил — это то что в неправильном случае потоки перестают переключатся во время выполнения запросов к базе (не ставить же для каждого запроса sched_yield). Но даже если бы всё и блокировалось на запросах всё-равно производительность выше должна получатся.
Re[9]: проблема с pthread
От:
Аноним
Дата:
10.09.03 07:31
Оценка:
N>Вот в том то и дело что все потоки остоновились кто на cond_wait, кто на recv, а в это время почему то в топе что-то. И у меня только один подозреваемый — это шедулер.
А что это что-то? у него наверное, есть pid и имя?
Может это lib'а доступа к БД запускает какой-нибудь свой thread?
N>Это всё делел, получил результаты которые выше вкратце описал. Единственное подозрительное заметил — это то что в неправильном случае потоки перестают переключатся во время выполнения запросов к базе (не ставить же для каждого запроса sched_yield). Но даже если бы всё и блокировалось на запросах всё-равно производительность выше должна получатся.
IMHO sched_yield не поможет, т.к. ты не можешь вызвать его ВОВРЕМЯ выполнения запроса к БД, т.е. либо ты вызываешь sched_yield() и она reshedule'ит thread'ы либо ты вызываешь ф-ию работы с БД и она делает то, что хочет (возможно, крутит циклы, но думаю, это не так — иначе загрузка была бы 100%).
Может у тебя один connect к БД на всех и они на нём блокируются?
Здравствуйте, Аноним, Вы писали:
N>>Вот в том то и дело что все потоки остоновились кто на cond_wait, кто на recv, а в это время почему то в топе что-то. И у меня только один подозреваемый — это шедулер.
А>А что это что-то? у него наверное, есть pid и имя?
Мой процесс в топе вверху что-то делает хотя все потоки остоновлены.
А>Может это lib'а доступа к БД запускает какой-нибудь свой thread?
Это libpq для PostreSql, раньше такого за ней не замечал.
N>>Это всё делел, получил результаты которые выше вкратце описал. Единственное подозрительное заметил — это то что в неправильном случае потоки перестают переключатся во время выполнения запросов к базе (не ставить же для каждого запроса sched_yield). Но даже если бы всё и блокировалось на запросах всё-равно производительность выше должна получатся.
А>IMHO sched_yield не поможет, т.к. ты не можешь вызвать его ВОВРЕМЯ выполнения запроса к БД, т.е. либо ты вызываешь sched_yield() и она reshedule'ит thread'ы либо ты вызываешь ф-ию работы с БД и она делает то, что хочет (возможно, крутит циклы, но думаю, это не так — иначе загрузка была бы 100%).
Может помочь но извращатся нужно конкретно, я это и имел ввиду, например запустить его асинхронно, ну а потом......
А>Может у тебя один connect к БД на всех и они на нём блокируются?
Нет не один, libpq в таких случаях вобще падает, конекты по одному на поток, открываются в начале работы программы.
Посмотри в доке к базе — что там сказано про работу в многопоточной среде. Напр. в mysql нужно вызывать из каждого потока ф-ию инициализации библиотеки в его контексте.
Здравствуйте, naje, Вы писали:
А>>А что это что-то? у него наверное, есть pid и имя?
N>Мой процесс в топе вверху что-то делает хотя все потоки остоновлены.
А>>Может это lib'а доступа к БД запускает какой-нибудь свой thread?
N>Это libpq для PostreSql, раньше такого за ней не замечал.
Ну так подцепись к нему gdb и посмотри кто и чего делает.