Сокеты и многопоточность
2) Оптимально ли создавать 200-300 потоков в одном приложении, каждый из которых будет обрабатывать свой сокет?
recv с флагом MSG_PEEK. Еще есть функция select, но с помощью этой функции по-моему можно узнать есть ли на принимающем сокете данные в принципе, но не их кол-во. Подробности в MSDN.
UNIX разработка сетевых приложений./У. Стивене. — СПб.: Питер, 2003.
13.7. Сколько данных находится в очереди? стр 408
>2) Оптимально ли создавать 200-300 потоков в одном приложении, каждый из которых будет обрабатывать свой сокет?
Об этом в этой книге тоже есть глава 23. В кратце рекомендуется пользоваться библиотекой pthread, так как затраты памяти меньше, и межпотоковая передача данных лучше организована. В книге есть примеры как это сделать.
UNIX разработка сетевых приложений./У. Стивене. — СПб.: Питер, 2003.
13.7. Сколько данных находится в очереди? стр 408
>2) Оптимально ли создавать 200-300 потоков в одном приложении, каждый из которых будет обрабатывать свой сокет?
Об этом в этой книге тоже есть глава 23. В кратце рекомендуется пользоваться библиотекой pthread, так как затраты памяти меньше, и межпотоковая передача данных лучше организована. В книге есть примеры как это сделать.[/quote]
А разве автор написал где-то что у него *nix ОС?
[quote=Steps09]1) Есть ли в С++ фунция, которая сообщает количество необработаных байт в сокете (байты которые ещё не получены функцыей recv() ).[/quote]
Любая функция Си может быть использована в С++. Надеюсь Америку тут не открыл? Возможно Вас интересует какая-то конкретная библиотека? или же Вы можете создать хоть свою собственную функцию на напримере библиотечной.
[quote=Steps09]2) Оптимально ли создавать 200-300 потоков в одном приложении, каждый из которых будет обрабатывать свой сокет?
[/quote]
Тут нужно не теоретизировать, а больше практиковать. Вопрос в том, будут ли сообщаться между собой потоки и не выльется ли синхронизации между потоками и борьба за ресурсы в большую проблему для вас, а то и геморой... И не станет ли скорость работы определяющим фактором для вас.
Можно повысить скорость работы приложения с помощью средств параллелизации, типа OpenMP ->
http://openmp.org/wp/
http://ru.wikipedia.org/wiki/OpenMP
или же OpenMPI ->
http://www.open-mpi.org/
OpenMP - просто, быстро, почти без гемора, включение разного рода аннотаций в коде.
OpenMPI - разработка сложна и т.д. и т.п. Зато функций и преимуществ поболее.
Корече говоря, нужно просто пробовать, постепенно наращивая колличесво потоков.
Если ты под виндами, то готов поспорить, что у тебя и без этого на машине их уже более трёхсот (загляни во вкладку "быстродействие" в диспетчере задач). Меня скорость устраивает, а тебя?
Вообще-то, OpenMP и MPI - две большие разницы. OpenMP работает по модели с общей памятью, MPI - с распределённой, путём обмена сообщениями (MPI = Message Passing Interface). Параллелизм OpenMP, в зависимости от реализации, основан на создании потоков и нитей (fibers, легковесных потоков). Единица параллельного выполнения в MPI - процесс. Иными словами, MPI (мне, кстати, больше понравился MPICH) имеет смысл использовать лишь в распределённых и кластерных системах, в то время как OpenMP, в данном случае, малополезна: концепция последовательно-параллельных секций, если "создавать 200-300 потоков в одном приложении, каждый из которых будет обрабатывать свой сокет", работать и поддерживаться будет плохо. Если же речь идёт о Windows, то преимущества её использования в большом проекте выглядят ещё более сомнительно.
Прекрасная выдержка из учебников. Всю эту теорию я сам прекрасно знаю, мог и не стараться так расписывать :) Насчет OpenMP - никогда не пробовал; товарищи советовали. Насчет OpenMPI - похоже ты его никогда не пробовал или мало с ним работал. Скажи мне пожалуйста, а что же тебе мешает использовать этот "fraimework" в локальных задачах одной программы, не кластеров и не распред. сетей??? У меня это почему-то получается... и у developer'ов Sun Solaris это прекрасно получается....видимо что-то мы тут упустили, вот незадача то.
Средства параллелизации в Windows вообще сомнительны, как и латентность нитей в этой ОС.
Почти три года своей жизни посвятил связке OpenMP + MPI + Intel C++ Compiler. Больше и под страхом пыток не сяду.
Вкратце, применительно к данной задаче, описать свой framework сможешь? Пусть, например, борьба между потоками (и, соответственно, клиентами) ведётся за консольный вывод.
Ты просто не умеешь их готовить :)
Ну например возмем самую простенькую функцию:
#include "mpi.h"
main(int argc, char** argv) {
int my_rank; /* Ранг процесса */
int p; /* Количество процессов */
int source; /* Ранг посылающего */
int dest; /* Ранг принимающего */
int tag = 50; /* Тэг сообщений */
char message[100]; /* Память для сообщения */
MPI_Status status; /* Статус возврата */
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
MPI_Comm_size(MPI_COMM_WORLD, &p);
if (my_rank != 0) {
sprintf(message, "Привет из процесса %d!", my_rank);
dest = 0;
/* Используется strlen(message)+1
чтобы включить '\0' */
MPI_Send(message, strlen(message)+1,
MPI_CHAR, dest, tag, MPI_COMM_WORLD);
} else { /* my_rank == 0 */
for (source = 1; source < p; source++) {
MPI_Recv(message, 100, MPI_CHAR, source, tag,
MPI_COMM_WORLD, &status);
printf("%s\n", message);
}
}
MPI-Finalize();
} /* main */
bash-3.2$ mpirun -np 4 mpi_helloworld
далее понятно что произойдет. Эта функция породит 4 потока срествами MPI. Этот "шаблон" функции, можно к примеру использовать в привычном коде, в качестве функции с которой начинается выполнение какого-либо из потоков (остается только реализовать собственный вариант функции "MPI"). А затем - привычное управление борьбой за ресурсы - семафоры, переменнные состояния,мьютексы и т.д. Средствами MPI можно добиться уменьшения времени выполнения задания в привычном потоке.
Можно также реализовать (к примеру) трапецидальную сортировку средствами MPI:
#include "mpi.h"
float f(float x) {
float return_val;
/* Вычисляет f(x).
Возвращает результат в return_val. */
. . .
return return_val;
}
float Trap(float local_a, float local_b, int local_n,
float h) {
float integral; /* Результат вычислений */
float x;
int i;
integral = (f(local_a) + f(local_b))/2.0;
x = local_a;
for (i = 1; i <= local-n-1; i++) {
x += h;
integral += f(x);
}
integral *= h;
return integral;
} /* Trap */
main(int argc, char** argv) {
int my_rank; /* Ранг процесса */
int p; /* Количество процессов */
float a = 0.0; /* Левая граница */
float b = 1.0; /* Правая граница */
int n = 1024; /* Количество трапеций */
float h; /* Ширина трапеции */
float local_a; /* Левая граница для процесса */
float local_b; /* Правая граница для процесса */
int local_n; /* Количество вычисляемых трапеций */
float integral; /* Значение интеграла по интервалу */
float total; /* Общий интеграл */
int source; /* Процесс, посылающий интеграл */
int dest = 0; /* Пункт назначения процесс 0 */
int tag = 50;
MPI_Status status;
MPI_Init(&argc, &argv);
/* Определить ранг процесса */
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
/* Определить количество процессов */
MPI_Comm_size(MPI_COMM_WORLD, &p);
h = (b-a)/n; /* h одинаково для всех процессов */
local_n = n/p; /* Получить количество трапеций */
/* Вычислить границы интервала и частный интеграл*/
local_a = a + my_rank*local_n*h;
local_b = local_a + local_n*h;
integral = Trap(local_a, local_b, local_n, h);
/* Суммировать все интегралы */
if (my_rank == 0) {
total = integral;
for (source = 1; source < p; source++) {
MPI_Recv(&integral, 1, MPI_FLOAT,
source, tag, MPI_COMM_WORLD, &status);
total += integral;
}
} else {
MPI_Send(&integral, 1, MPI_FLOAT, dest,
tag, MPI_COMM_WORLD);
}
/* Вывод результата */
if (my_rank == 0) {
printf("C n = %d трапециями, оценка\n", n);
printf("интеграла от %f до %f = %f`\n",
a, b, total);
}
/* Завершить приложение MPI */
MPI_Finalize();
} /* main */
или же (тоже к примеру) реализовать обмен сообщениями:
float* b_ptr, int* n_ptr)
{
int source = 0; /* Локальные переменные */
int dest; /* используемые MPI_Send и MPI_Recv */
int tag;
MPI_Status status;
if (my_rank == 0) {
printf("Введите a, b, и n\n");
scanf("%f %f %d", a_ptr, b_ptr, n_ptr);
for (dest = 1; dest < p; dest++) {
tag = 30;
MPI_Send(a_ptr, 1, MPI_FLOAT, dest, tag,
MPI_COMM_WORLD);
tag = 31;
MPI_Send(b_ptr, 1, MPI_FLOAT, dest, tag,
MPI_COMM_WORLD);
tag = 32;
MPI_Send(n_ptr, 1, MPI_INT, dest, tag,
MPI_COMM_WORLD);
}
} else {
tag = 30;
MPI_Recv(a_ptr, 1, MPI_FLOAT, source, tag,
MPI_COMM_WORLD, &status);
tag = 31;
MPI_Recv(b_ptr, 1, MPI_FLOAT, source, tag,
MPI_COMM_WORLD, &status);
tag = 32;
MPI_Recv(n_ptr, 1, MPI_INT, source, tag,
MPI_COMM_WORLD, &status);
}
}/* Get_data */
[QUOTE=Der Meister ]Больше и под страхом пыток не сяду.[/QUOTE]
Я с тобой согласен, MPI очень сложная штука, но насчет OpenMP говорили что все прям просто как раз, два, три.....:)
[QUOTE=Der Meister]Ты просто не умеешь их готовить :)[/QUOTE]
Дак и не собирался. Пишу немного под другую платформу.
Что-то отдалилсь от темы...
Мда....а про автора то мы и забыли, кинувшись в дебаты :D
1) Код, в котором три процесса посылают текст четвёртому
2) Код вычисления интеграла методом трапеций (опять же, разными процессами)
3) Код, в котором процессам рассылается по три числа с плавающей запятой
Кстати, во всех случаях, гораздо проще использовать коллективные операции. Ещё не понял [QUOTE=Jail]Средствами MPI можно добиться уменьшения времени выполнения задания в привычном потоке.[/QUOTE]То есть? В приведённом коде, вместо межпотокового взаимодействия, мы получаем уже межпроцессное, т. е. единсвенный способ получить доступ к ресурсу - прогнать данные как минимум по трубе (pipe). Как, при таком подходе, можно уменьшить время выполнения? К тому же, процесс - это уже слижком накладно.
В приведённых же примерах, использование MPI вполне обосновано, если речь идёт о распределённых вычислениях. Но я-то просил описать кусочек модели для[QUOTE=Zorkus]...растопырить 300 портов, и слушать их для организации чата..или что-то в этом роде.[/QUOTE], реализованный средствами MPI. Без кода, так гораздо проще.
Промимо всего прочего, приведённые куски кода совсем не используют потенциал MPI. Места, гда появляются MPI_Send/MPI_Recv, всегда читаются сложно, и их очень сложно отлаживать.
Кстати, по поводу OpenMP. Нередко (мягко сказал) тот же Intel C++ Compiler for Linux лучше распараллеливает вычисления без неё, чем с ней.
Относительно первого, то мне подходит MSG_PEEK, просто во время первого прочтения МСДНа я подумал, что он отличается от простого вызова gets(), тем что не убирает данные из входящего буфера (не знаю в каком состоянии я это читал, но что-то не заладилось у меня с его инфой).
Относительно потоков, то меня интересовало не слишком ли они дадут нагрузку на дескриптор процеса (никогда не работал с ними, но в данном случае это наверно оптимальное решение).
Относительно ОС, то обе.
Относительно 300 портов, то это слишком, мне и одного хватит.
Каждый сокет расчитан на р2р общение.
Qt я на данный момент использовать не буду (пока не подойду к GUI), а поточность и сокеты для обеих ОС на данной стадии мне будет легче реализовать без него.
Это нужно экспериментировать и потом так же много и вдумчиво анализировать результаты.
Я собираюсь написать битторрент клиент.
Вот на что будут тратится основные потоки и сокеты:
- по одному потоку и сокету на трекер
- по одному потоку и сокету на сида/лича (подключённого)
- один поток и сокет для прослушки входящих подключений.
- поток на менеджера подключений
Борьбы за ресурсы как таковой почти не будет.
Основными фронтами будут
- между трекерными потоками и потоком менеджера (легко организовывается с помощю критических секцый)
- между самими р2р подключениями за доступ к файлам (теми же секцыями)
Если видите явные недостатки, то скажите.
Не могу найти примеров для кластерных систем, а не многопроцессорных. Такое впечатление, что это знает каждый ребенок, но никто нигде не подумал об этом написать. Везде только локальное взаимодействие процессов.
Книжек - вагон.
Шпаковский, Серикова - Программирование многопроцессорных систем в стандарте MPI.pdf
Антонов - параллельное программирование с использованием стандарта MPI.pdf
bukatov_progr_multiprocessors.pdf
Но за книжки спасибо. :)
Примеры кода будут лишены смысла до тех пор, пока вы не поймёте саму философию MPI. Поэтому я насоветовал вам книжек.
Там ещё есть коллективные операции и топологии вычислений, понять которые тоже желательно.