Модераторы: Snowy, bartram, MetalFan, bems, Poseidon, Riply

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Многопоточное программирование, несколько вопросов 
:(
    Опции темы
ilyalyu
Дата 1.4.2007, 14:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 135
Регистрация: 25.10.2006

Репутация: нет
Всего: нет



Эти вопросы относятся по-видимому не конкретно к c++, а к многопоточному программированию в целом.

1. Вопрос первый. При вызове функций место для локальных переменных выделяется в стеке. Допустим, внутри двух разных потоков произошел вызов функций. Правильно ли, что стек будет выглядеть следующим образом:

| Начало стека (занято)
| Место под локальные переменные потока 1
| Место под локальные переменные потока 2
| Конец стека (свободно)

Если так, то правильно ли, что выход из функции, вызванной внутри потока 1, сможет произойти только после завершения функции, вызванной внутри потока 2? В противном случае получится следующее:

| Начало стека (занято)
| Середина стека (свободно - !!!)
| Место под локальные переменные потока 2
| Конец стека (свободно)

И более глобальный вопрос - нужно ли вообще думать обо всем написанном выше или все эти проблемы решаются автоматически.

2. Я использую в программе критические секции. Для того чтобы исключить недопонимание, отмечу, что число критических секций НЕ ЕСТЬ число входов/выходов из критической секции (т.е. критическая секция может быть одна, а число входов/выходов много). Так вот вопрос в следующем. (1) Насколько критичным для скорости выполнения программы является использование большого количества критических секций (допустим порядка 1000). (2) Тот же вопрос, но уже относительно входов/выходов из критическую секцию. Например, насколько замедлится программа, если входы/выходы будут происходить через каждые 10 строчек (при этом считаем, что медленных операций, типа чтения/записи в файл, там нет).
PM MAIL   Вверх
Daevaorn
Дата 1.4.2007, 14:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2155
Регистрация: 29.11.2004
Где: Москва

Репутация: нет
Всего: 70



у каждого потока свой стек
PM MAIL WWW   Вверх
ilyalyu
Дата 1.4.2007, 14:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 135
Регистрация: 25.10.2006

Репутация: нет
Всего: нет



Цитата(Daevaorn @ 1.4.2007,  14:27)
у каждого потока свой стек

Ясно. С первым вопросом разобрались. Спасибо!!!

Кстати, забыл спросить. А насколько эффективно использование большого количества потоков. Например, порядка тысячи. Например, не окжется ли, что переключение между потоками будет занимать 90% процессорного времени и т.д.

Это сообщение отредактировал(а) ilyalyu - 1.4.2007, 14:42
PM MAIL   Вверх
dumb
Дата 1.4.2007, 17:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


sceloglauxalbifacies
****


Профиль
Группа: Экс. модератор
Сообщений: 2929
Регистрация: 16.6.2006

Репутация: 7
Всего: 158



Цитата(ilyalyu @  1.4.2007,  14:42 Найти цитируемый пост)
А насколько эффективно использование большого количества потоков. Например, порядка тысячи.

в общем случае - очень неэффективно. особенно "порядка тысячи".
PM MAIL   Вверх
W4FhLF
Дата 1.4.2007, 17:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


found myself
****


Профиль
Группа: Участник Клуба
Сообщений: 2831
Регистрация: 2.12.2006

Репутация: 6
Всего: 121



Цитата(ilyalyu @  1.4.2007,  14:16 Найти цитируемый пост)
2. Я использую в программе критические секции. Для того чтобы исключить недопонимание, отмечу, что число критических секций НЕ ЕСТЬ число входов/выходов из критической секции (т.е. критическая секция может быть одна, а число входов/выходов много). Так вот вопрос в следующем. (1) Насколько критичным для скорости выполнения программы является использование большого количества критических секций (допустим порядка 1000). (2) Тот же вопрос, но уже относительно входов/выходов из критическую секцию. Например, насколько замедлится программа, если входы/выходы будут происходить через каждые 10 строчек (при этом считаем, что медленных операций, типа чтения/записи в файл, там нет).


Ну как сказать, смотря, что ты вкладываешь в понятия "быстро" и "медленно". Критические секции юзермодный механизм синхронизации, т.е. переходов между уровня привелегий не будет, это уже плюс. А в остальном ну выделяется память системой, заполняется структура, далее сравнивается и в конце-концов освобждается. Сам прикидывай насколько это быстро. 
А какие операции ты выполняешь в секции? Если тебе нужно выполнить только чтение/запись в память, то может обойдёшься стандартными Inetlocked-функциями?

Добавлено через 2 минуты и 18 секунд
Цитата(ilyalyu @  1.4.2007,  14:42 Найти цитируемый пост)
Кстати, забыл спросить. А насколько эффективно использование большого количества потоков. Например, порядка тысячи. Например, не окжется ли, что переключение между потоками будет занимать 90% процессорного времени и т.д.


Если ты выполняешь синхронные действия, т.е. действия, которые не заставляют ждать ответа от сторонних приложений или, к примеру, из сокета, то даже 2 потока не дадут тебе прироста больше 10%, а уж 1000 вообще сведут на 0 и даже угонят в минус, твою оптимизацию.


--------------------
"Бог умер" © Ницше
"Ницше умер" © Бог
PM ICQ   Вверх
ilyalyu
Дата 1.4.2007, 18:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 135
Регистрация: 25.10.2006

Репутация: нет
Всего: нет



dumb, W4FhLF, спасибо за коментарии.

Для того чтобы всем облегчить жизнь, напишу, для чего я использую потоки. Я пишу чат-сервер с использованием сокетов. Соответственно, большинство потоков просто ожидают данных из сокета. Весь вопрос в том, что происходит в это время. Я в меру своей необразованности представляю это так: переодически происходит переключение между разными потоками и они проверяют, не поступило ли данных. Соответственно, время расходуется на переключение и проверку сокетов. Вот вопрос, если брать в расчет только эти операции, то сколько потоков одновременно можно потянуть. Дело в том, что я уже написал чат-сервер на PHP без потоков, но он уже при 100 юзерах онлайн грузит процессор на 30% и более. Мне надо, чтобы сервер нормально работал при 1000+ юзерах онлайн.

Вопрос насчет критических секций разрешился с помощью тестирования. 2,5 миллиона входов и выходов за одну секунду на 667мгц. Думаю, мне этого вполне достаточно smile
PM MAIL   Вверх
ilyalyu
Дата 1.4.2007, 19:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 135
Регистрация: 25.10.2006

Репутация: нет
Всего: нет



Теперь протестировал работу большого количества потоков. Код приблизительно такой:

Код

function g(p: Pointer): Longint;
begin
  while true do begin
    Sleep(1000);
    EnterCriticalSection(__CSIOScreen);
    LeaveCriticalSection(__CSIOScreen);
  end
end;

for i := 1 to 10000 do begin BeginThread(g);


Внутри потоков ничего не происходит, они просто "просыпаются" раз в секунду. Оказалось, что на создание 10 тысяч потоков уходит 30 секунд. То есть 300 потоков в секунду (что-то долго...). После этого программа потребляет 2% от 677мгц. То есть одновременно могут функционировать порядка 500 тысяч потоков. Памяти все это занимает 90мб, то есть 9кб на поток.
PM MAIL   Вверх
Бонифаций
Дата 1.4.2007, 20:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 827
Регистрация: 15.9.2005
Где: Brisbane

Репутация: нет
Всего: 40



  • По умолчанию каждый трид (в линуксе) выделяет 2М памяти под стек. То есть на 1000 клиентов вам понадобится около 2 гиг памяти только на то чтобы ваша программа как-то дышала.. Если у вас физической памяти меньше, то наличие такого количества тридов приведет к дикому свапированию памяти. 
  •  По умолчанию в glibc внутренние структуры заточены под максимум 1024 трида. Если у вас их будет больше, необходима перекомпиляция glibc. Это бооольшая жывопырка
  •  Обычно такие задачи с большим количеством вялых клиентов решаются при помощи асинхронной работы сокетов. Смотрите функции select и poll



--------------------
 Бонифаций.
 
PM MAIL ICQ Skype GTalk Jabber YIM   Вверх
ilyalyu
Дата 1.4.2007, 22:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 135
Регистрация: 25.10.2006

Репутация: нет
Всего: нет



Бонифаций, спасибо за коментарий. Посмотрел по интернету, что пишут про поддержку потоков и пришел к предварительному выводу, что под Windows лучше использовать потоки (и это вроде бы подтверждается моими тестами - 10000 потоков потребляют всего 1-2% процессорного времени), а под Linux лучше использовать операцию Select.

Вопрос - насколько этот вывод правильный?

Что касается размера стека, то его можно задавать в функции BeginThread. А разве под Linux стек не растет динамически, как под Windows? Вот уж не ожидал. На Windows обычно всех собак вешают, а выходит, что и поддержка потоков у него лучше, и о размере стека в отличие от Linux не приходится беспокоиться...
PM MAIL   Вверх
Бонифаций
Дата 1.4.2007, 22:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 827
Регистрация: 15.9.2005
Где: Brisbane

Репутация: нет
Всего: 40



PS PS. то что я присал относится к linuxthread. В NPTL другая кухня. А для чатов лучше использовать select в любом случае.



--------------------
 Бонифаций.
 
PM MAIL ICQ Skype GTalk Jabber YIM   Вверх
ilyalyu
Дата 1.4.2007, 22:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 135
Регистрация: 25.10.2006

Репутация: нет
Всего: нет



Я пишу на Free Pascal. Пока я там нашел select только под Linux. Под Windows его просто нет или я пока не нашел. Но я еще поищу. Спасибо.
PM MAIL   Вверх
Void
Дата 1.4.2007, 22:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


λcat.lolcat
****


Профиль
Группа: Участник Клуба
Сообщений: 2206
Регистрация: 16.11.2004
Где: Zürich

Репутация: нет
Всего: 173



ilyalyu, создал 10000 потоков? Отлично, а теперь посмотри в диспетчере задач, сколько потоков у твоего процесса. Окажется чуть более двух тысяч. Это предел для процесса: стеки потоков занимают всё адресное пространство. Своп не начинается, потому что память не закоммичена.
Лучше не использовать модель «один клиент — один поток», это ж не Эрланг всё-таки.
В Windows для таких вещей рекомендуется использовать пулы потоков.


--------------------
“Coming back to where you started is not the same as never leaving.” — Terry Pratchett
PM MAIL WWW GTalk   Вверх
ilyalyu
Дата 1.4.2007, 23:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 135
Регистрация: 25.10.2006

Репутация: нет
Всего: нет



В диспечере задач я такой информации не нашел., но при проверке с помощью приведенного ниже кода выяснилось, что создается порядка 8000 потоков, т.е. действительно есть ограничение. 

Код

function g(p: Pointer): Longint;
begin
  EnterCriticalSection(CS);
  Count := Count+1;
  LeaveCriticalSection(CS);
  while True do Sleep(1000);
end;

for i := 1 to 10000 do BeginThread(g);
writeln(Count);


Вашу идею я понял. Можно проверять сокеты на наличие данных, а затем уже обрабатывать их внутри нескольких потоков. Я согласен, что это наиболее оптимальное решение. Вот только найду, где select под windows... Точнее я уже нашел - в юните winsock. Осталось теперь только help к ней найти smile

Это сообщение отредактировал(а) ilyalyu - 1.4.2007, 23:15
PM MAIL   Вверх
dumb
Дата 2.4.2007, 02:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


sceloglauxalbifacies
****


Профиль
Группа: Экс. модератор
Сообщений: 2929
Регистрация: 16.6.2006

Репутация: 7
Всего: 158



Цитата(ilyalyu @  1.4.2007,  23:14 Найти цитируемый пост)
for i := 1 to 10000 do BeginThread(g);
writeln(Count);

все твои "замеры" некорректны(про некоторые моменты уже сказали) или просто содержат ошибку - как процитированный кусок.
настоятельно советую прочитать несколько статей про многопоточность.
начать можно с этой статьи.

Цитата(ilyalyu @  1.4.2007,  19:27 Найти цитируемый пост)
То есть одновременно могут функционировать порядка 500 тысяч потоков.

сильно сомневаюсь. даже если такое кол-во удастся запустить, то вся система будет "пытаться выжить", причем не факт, что это ей удастся. smile
PM MAIL   Вверх
Pulse69
Дата 2.4.2007, 09:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 138
Регистрация: 28.4.2006
Где: Хабаровск

Репутация: нет
Всего: 10



Цитата(ilyalyu @  1.4.2007,  19:27 Найти цитируемый пост)
То есть одновременно могут функционировать порядка 500 тысяч потоков.

Очень вряд ли что такое число потков в реальной работе не подвесит Вашу систему.
Модель "один клиент - один поток" является самой неэффективной. Вы вряд ли сможете 
её использовать если число подключенных клиентов превысит 500-600.
Единственный способ в Windows обрабатывать тысячи клиентов - это IO Completion Ports.
По разным оценкам, приложение на основе IOCP могут обсуживать до 32000 клиентов.
Если Вам нужно действительно эффективное приложение, стоит всерьёз рассмотреть
возможность использования IOCP. Поверьте, разница действительно впечатляет.

Для Winsock начать можно с этой статьи.
http://msdn.microsoft.com/msdnmag/issues/1000/Winsock/
--------------------
Ctrl+Alt+Reset 
PM MAIL   Вверх
MAKCim
Дата 2.4.2007, 09:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: нет
Всего: 207



Цитата(Бонифаций @  1.4.2007,  22:31 Найти цитируемый пост)
PS PS. то что я присал относится к linuxthread

откуда сведения про 2Мб?


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
Бонифаций
Дата 2.4.2007, 10:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 827
Регистрация: 15.9.2005
Где: Brisbane

Репутация: нет
Всего: 40



1) исходники glibc (linuxthread/internals.h)
2) Много раз во всякой документации встречалось. linuxthread default stack size 2M, windows - 1M freebsd - 64k

Добавлено через 3 минуты и 32 секунды
для интереса в гугле поискал пример такой документации. Linuxthread faq:

D.10: My application needs to create thousands of threads, or maybe even more. Can I do this with LinuxThreads?
No. You're going to run into several hard limits:

    * Each thread, from the kernel's standpoint, is one process. Stock Linux kernels (version 2.2 and earlier) are limited to at most 512 processes for the super-user, and half this number for regular users. This can be changed by changing NR_TASKS in include/linux/tasks.h and recompiling the kernel. On the x86 processors at least, architectural constraints seem to limit NR_TASKS to 4090 at most. (It seems that 2.4 kernels have higher limits, though.)
    * LinuxThreads contains a table of all active threads. This table has room for 1024 threads at most. To increase this limit, you must change PTHREAD_THREADS_MAX in the LinuxThreads/glibc sources and recompile.
    * By default, each thread reserves 2M of virtual memory space for its stack. This space is just reserved; actual memory is allocated for the stack on demand. But still, on a 32-bit processor, the total virtual memory space available for the stacks is on the order of 1G, meaning that more than 500 threads will have a hard time fitting in. You can overcome this limitation by moving to a 64-bit platform, or by allocating smaller stacks yourself using the setstackaddr attribute.
    * Finally, the Linux kernel contains many algorithms that run in time proportional to the number of process table entries. Increasing this number drastically will slow down the kernel operations noticeably. 


--------------------
 Бонифаций.
 
PM MAIL ICQ Skype GTalk Jabber YIM   Вверх
ilyalyu
Дата 2.4.2007, 12:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 135
Регистрация: 25.10.2006

Репутация: нет
Всего: нет



всем спасибо. на основании приведенных выше коментариев я решил пересмотреть концепцию программы. действовать будут так:

1 поток: в режиме accept, обрабатывает новые соединения.
1 поток: в режиме select, ожидает данные из сокетов.
8-32 потоков: на подхвате, читают и обрабатывают данные из сокетов.

функцию select я нашел. под windows она находится в юните winsock, под linux в юните oldlinux. так что больших проблем с совместимостью, надеюсь, не будет.

за ссылки также спасибо.

по поводу стека повторяю, что размер стека можно указать в качестве параметра при создании потока (по крайней мере на Free Pascal).
PM MAIL   Вверх
Страницы: (2) [Все] 1 2 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: WinAPI и системное программирование"
Snowybartram
MetalFanbems
PoseidonRrader
Riply

Запрещено:

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Delphi обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи
  • 99% ответов по WinAPI можно найти в MSDN Library, оставшиеся 1% здесь

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, bartram, MetalFan, bems, Poseidon, Rrader, Riply.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: WinAPI и системное программирование | Следующая тема »


 




[ Время генерации скрипта: 0.0644 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.