Увеличить производительность многопоточностью

Ответить
Nyashka
Сообщения: 40
Зарегистрирован: 19 мар 2013, 13:06

Увеличить производительность многопоточностью

Сообщение Nyashka » 18 авг 2014, 20:17

Заранее планировал вынести распараллеленные задачи по потокам, дабы получить ускорение при обработке на многоядерных процессорах. Однако как показали тесты простое создание потока (Timer + TimerTask) не перемещает обработку на дополнительное ядро, и ,следовательно, не привносит ни какого приемущества. Отсюда вопрос: Как вообще реализуется параллельное программирование на Java?

Аватара пользователя
Mikhail_dev
Сообщения: 2386
Зарегистрирован: 09 янв 2012, 14:45
Откуда: Самара

Re: Увеличить производительность многопоточностью

Сообщение Mikhail_dev » 18 авг 2014, 20:56

В Android каждая программа - это собственная копия виртуальной машины, которая крутится в одном процессе. Я так понимаю, что многоядерные процессоры, обрабатывают разные рпоцессы, но не потоки. Другими словами, они обрабатывают в рамках одного ядра все потоки одного процесса.
Как вообще реализуется параллельное программирование на Java?
Зависит от реализации виртуальной машины и от самой ОС

Viewer
Сообщения: 180
Зарегистрирован: 30 апр 2014, 11:42

Re: Увеличить производительность многопоточностью

Сообщение Viewer » 19 авг 2014, 07:53

Логика распараллеливания на многоядерных процессорах целиком и полностью лежит на операционной системе (возможно даже и самого процессора) и может быть реализована на разных устройствах по-разному и напрямую влиять на это со стороны пользовательского ПО врядли получится. На устройстве могут выполнятся одновременно десятки процессов с сотнями параллельных потоков, но если они не сильно загружают процессор, то все они будут выполняться на одном ядре. Но в тоже время и один многопоточный процесс вполне может загрузить все ядра.
Если интересно, здесь некоторые исследования на эту тему http://bigflake.com/systrace/

Nyashka
Сообщения: 40
Зарегистрирован: 19 мар 2013, 13:06

Re: Увеличить производительность многопоточностью

Сообщение Nyashka » 19 авг 2014, 09:49

Спасибо за исчерпывающий ответ. Очень жаль что в моем случае высокая нагрузка будет проигнорирована из за того что она перемежается с полным бездействием в ожидании отрисовки.
С другой стороны радует что мой телефон не будет садиться в два раза быстрее из за каких нибудь умников неграмотно использовавших многоядерность в каких нибудь часах или плейере

Аватара пользователя
altwin
Сообщения: 1951
Зарегистрирован: 13 ноя 2013, 14:46

Re: Увеличить производительность многопоточностью

Сообщение altwin » 19 авг 2014, 11:10

https://developer.qualcomm.com/blog/mul ... s-part-1-2
https://developer.qualcomm.com/blog/mul ... s-part-2-2
все остальное за рамками android sdk. Но ничего сложного тут нет, это стандартная(для posix систем) С -шная функция pthread, почитать можно тут: https://08926976467793358646.googlegrou ... w=1&part=4
Viewer писал(а):Логика распараллеливания на многоядерных процессорах целиком и полностью лежит на операционной системе (возможно даже и самого процессора) и может быть реализована на разных устройствах по-разному и напрямую влиять на это со стороны пользовательского ПО врядли получится.
никакого отношения не имеет модель posix к типу девайсов и реализованна она на уровне ядра. Я пока не встречал производителей телефонов на базе android, которые бы переписывали ядро, и это был бы маразм, да и ресурсов нет у них. Не нужно путать unix и windows. Логика в android как и в любой нормальной ОС, не на уровне ОС, а на уровне ядра и хоть это со стороны и выглядит похоже - это принципиально разные вещи. ядро изначально содержит в себе средства распаралеливания процессов, многопоточностью же занимается сам dalvik.

quote v.2^
***и напрямую влиять на это со стороны пользовательского ПО врядли получится - никаких проблем нет в работате с posix для пользователя, это не windows.
Изображение

Nyashka
Сообщения: 40
Зарегистрирован: 19 мар 2013, 13:06

Re: Увеличить производительность многопоточностью

Сообщение Nyashka » 19 авг 2014, 11:59

altwin писал(а): С -шная функция pthread, почитать можно тут: https://08926976467793358646.googlegrou ... w=1&part=4
Т.е. существует возможность собственноручно распараллелить свое приложение используя Сишную библиотеку? В таком случае может ли вызвать затруднение подключение такой библиотеки к эклипсу? Или придется писать на Си?

Аватара пользователя
altwin
Сообщения: 1951
Зарегистрирован: 13 ноя 2013, 14:46

Re: Увеличить производительность многопоточностью

Сообщение altwin » 19 авг 2014, 12:09

Nyashka писал(а):
altwin писал(а): С -шная функция pthread, почитать можно тут: https://08926976467793358646.googlegrou ... w=1&part=4
Т.е. существует возможность собственноручно распараллелить свое приложение используя Сишную библиотеку? В таком случае может ли вызвать затруднение подключение такой библиотеки к эклипсу? Или придется писать на Си?
Когда вы создаете поток - вызывается pthread и другого пути нет, вся модель многопоточности android -это классический posix. Вы же понимаете, что из dalvik вы не можете управлять kernel (ядром) ОС. Все, что вы моежете -это вызывать core функции -это суть работы jni. Т.е. если вам нужно не вызывать стандартные функции, а изменить модель многопоточности, вам нужен Cи и других варриантов нет, поскольку вам нужно изменить именно поведение pthread. Но это не имеет смысла в большинстве случаев, система довольно хорошо оптимизированна и по мере надобности/загрузки сама распределяет задачи по процессорам. Но вообще особенно в game dev часто практикуют ручное управление процессами и никаких проблем это не вызывает, это не более страшно, что классические malloc(), realloc(). Вся суть тут: https://github.com/android/platform_bio ... /pthread.h

P.S. с подключением к eclipse проблем нет, Вячеслав из r_id_team не плохую статью на эту тему уже писал: http://habrahabr.ru/post/203014/ , вопросы ему можете тут позадавать, когда ему наконец ноутбук привезут и у него будет хорошее настроение :mrgreen: Но опять же переписать pthread вы не сможете хотябы потому, что это было бы странно, но работать с api - без проблем, т.е. вызывая стандартные функции Bionic.
Изображение

Аватара пользователя
Foenix
Сообщения: 4201
Зарегистрирован: 20 окт 2012, 12:01

Re: Увеличить производительность многопоточностью

Сообщение Foenix » 19 авг 2014, 12:53

а за что ты нас так.. растопырил :-D
R.id.team

NullPointerException - что делать???
viewtopic.php?f=33&t=3899&p=28952#p28952
Где моя ошибка?
viewtopic.php?f=60&t=3198

Аватара пользователя
altwin
Сообщения: 1951
Зарегистрирован: 13 ноя 2013, 14:46

Re: Увеличить производительность многопоточностью

Сообщение altwin » 19 авг 2014, 13:00

Foenix писал(а):а за что ты нас так.. растопырил :-D
чтобы всем места хватило :)
Изображение

Viewer
Сообщения: 180
Зарегистрирован: 30 апр 2014, 11:42

Re: Увеличить производительность многопоточностью

Сообщение Viewer » 19 авг 2014, 13:14

С многопоточностью в Linux, pthread примерно ясно, но речь здесь совершенно не об этом, если я правильно понимаю речь идет о физических (или логических) ядрах процессора. Хотя с принципом - "можно все" спорить бесполезно, но весьма было бы любопытно увидеть работоспособный пример с запуском потока на конкретном ядре (скажем 2-м), да еще чтоб он был работоспособен хотябы на 10% девайсов.

Аватара пользователя
altwin
Сообщения: 1951
Зарегистрирован: 13 ноя 2013, 14:46

Re: Увеличить производительность многопоточностью

Сообщение altwin » 19 авг 2014, 13:27

Viewer писал(а):С многопоточностью в Linux, pthread примерно ясно, но речь здесь совершенно не об этом, если я правильно понимаю речь идет о физических (или логических) ядрах процессора. Хотя с принципом - "можно все" спорить бесполезно, но весьма было бы любопытно увидеть работоспособный пример с запуском потока на конкретном ядре (скажем 2-м), да еще чтоб он был работоспособен хотябы на 10% девайсов.
Вопервых распределяются не потоки, а процессы.
[syntax=c]
//compilation: gcc -o affinity affinity.c -lpthread

#define _GNU_SOURCE
#include <sched.h> //cpu_set_t , CPU_SET
#include <pthread.h> //pthread_t
#include <stdio.h>

void *th_func(void * arg);

int main(void) {
pthread_t thread; //the thread

pthread_create(&thread,NULL,th_func,NULL);

pthread_join(thread,NULL);

return 0;
}


void *th_func(void * arg)
{
//we can set one or more bits here, each one representing a single CPU
cpu_set_t cpuset;

//the CPU we whant to use
int cpu = 2;

CPU_ZERO(&cpuset); //clears the cpuset
CPU_SET( cpu , &cpuset); //set CPU 2 on cpuset


/*
* cpu affinity for the calling thread
* first parameter is the pid, 0 = calling thread
* second parameter is the size of your cpuset
* third param is the cpuset in which your thread will be
* placed. Each bit represents a CPU
*/
sched_setaffinity(0, sizeof(cpuset), &cpuset);

while (1);
; //burns the CPU 2

return 0;
}
[/syntax]

или просто для примера ( так делать не надо ):

[syntax=c]
double waste_time(long n)
{

double res = 0;
long i = 0;
while (i <n * 200000) {
i++;
res += sqrt(i);
}
return res;
}

void *thread_func(void *param)
{

unsigned long mask = 1; /* processor 0 */

/* bind process to processor 0 */
if (pthread_setaffinity_np(pthread_self(), sizeof(mask),
&mask) <0) {
perror("pthread_setaffinity_np");
}

/* waste some time so the work is visible with "top" */
printf("result: %f\n", waste_time(2000));

mask = 2; /* process switches to processor 1 now */
if (pthread_setaffinity_np(pthread_self(), sizeof(mask),
&mask) <0) {
perror("pthread_setaffinity_np");
}

/* waste some more time to see the processor switch */
printf("result: %f\n", waste_time(2000));
}


int main(int argc, char *argv[])
{

pthread_t my_thread;

if (pthread_create(&my_thread, NULL, thread_func, NULL) != 0) {
perror("pthread_create");
}
pthread_exit(NULL);
}
[/syntax]

для более общей картины можно посмотреть на такое:
[syntax=c]
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <sched.h>
#include <errno.h>

#include <unistd.h>

int getNumberOfCpus( void )
{
long nprocs = -1;
long nprocs_max = -1;

# ifdef _SC_NPROCESSORS_ONLN
nprocs = sysconf( _SC_NPROCESSORS_ONLN );
if ( nprocs < 1 )
{
//std::cout << "Could not determine number of CPUs on line. Error is " << strerror( errno ) << std::endl;
return 0;
}

nprocs_max = sysconf( _SC_NPROCESSORS_CONF );

if ( nprocs_max < 1 )
{
//std::cout << "Could not determine number of CPUs in host. Error is " << strerror( errno ) << std::endl;
return 0;
}

//std::cout << nprocs < " of " << nprocs_max << " online" << std::endl;
return nprocs;

#else
//std::cout << "Could not determine number of CPUs" << std::endl;
return 0;
#endif
}

void *pthread_Message( void *ptr )
{
sleep(10);
char *message;
message = (char *) ptr;
printf("%s \n", message);
cpu_set_t l_cpuSet;
int l_maxCpus;
int j;
unsigned long l_cpuBitMask;

CPU_ZERO( &l_cpuSet );
printf("get affinity %d\n",pthread_getaffinity_np(pthread_self() , sizeof( cpu_set_t ), &l_cpuSet ));
// printf("cpuset %d\n",l_cpuSet);
printf (" thread id %u\n", pthread_self());

if ( pthread_getaffinity_np(pthread_self() , sizeof( cpu_set_t ), &l_cpuSet ) == 0 )
for (int i = 0; i < 4; i++)
if (CPU_ISSET(i, &l_cpuSet))
printf("XXXCPU: CPU %d\n", i);
for (long i=0; i< 10000000000; ++i);
}

int main()
{
pthread_t thread1, thread2, thread3, thread4;
pthread_t threadArray[4];
cpu_set_t cpu1, cpu2, cpu3, cpu4;
const char *thread1Msg = "Thread 1";
const char *thread2Msg = "Thread 2";
const char *thread3Msg = "Thread 3";
const char *thread4Msg = "Thread 4";
int thread1Create, thread2Create, thread3Create, thread4Create, i, temp;

thread1Create = pthread_create(&thread1, NULL, &pthread_Message, (void*)thread1Msg);
sleep(1);
thread2Create = pthread_create(&thread2, NULL, &pthread_Message, (void*)thread2Msg);
sleep(1);
thread3Create = pthread_create(&thread3, NULL, &pthread_Message, (void*)thread3Msg);
sleep(1);
thread4Create = pthread_create(&thread4, NULL, &pthread_Message, (void*)thread4Msg);


CPU_ZERO(&cpu1);
CPU_SET(0, &cpu1);
temp = pthread_setaffinity_np(thread1, sizeof(cpu_set_t), &cpu1);
printf("setaffinity=%d\n", temp);
printf("Set returned by pthread_getaffinity_np() contained:\n");
for (i = 0; i < CPU_SETSIZE; i++)
if (CPU_ISSET(i, &cpu1))
printf("CPU1: CPU %d\n", i);

CPU_ZERO(&cpu2);
CPU_SET(1, &cpu2);
temp = pthread_setaffinity_np(thread2, sizeof(cpu_set_t), &cpu2);
for (i = 0; i < CPU_SETSIZE; i++)
if (CPU_ISSET(i, &cpu2))
printf("CPU2: CPU %d\n", i);

CPU_ZERO(&cpu3);
CPU_SET(2, &cpu3);
temp = pthread_setaffinity_np(thread3, sizeof(cpu_set_t), &cpu3);
for (i = 0; i < CPU_SETSIZE; i++)
if (CPU_ISSET(i, &cpu3))
printf("CPU3: CPU %d\n", i);

CPU_ZERO(&cpu4);
CPU_SET(3, &cpu4);
temp = pthread_setaffinity_np(thread4, sizeof(cpu_set_t), &cpu4);
for (i = 0; i < CPU_SETSIZE; i++)
if (CPU_ISSET(i, &cpu4))
printf("CPU4: CPU %d\n", i);

// pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpu1);



// pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpu1);

pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
pthread_join(thread3, NULL);
pthread_join(thread4, NULL);

return 0;
}
[/syntax]

Я повторю реализованна модель posix на уровне ядра, никакого вообще отношения к типу девайса -это не имеет, просто ядра доступны или нет, это определяется на уровне заголовков.

P.S. кстати именно posix модель обеспечивает в первую очередь переносимость и абсолютную независимость от типа устройтсва.
Изображение

Viewer
Сообщения: 180
Зарегистрирован: 30 апр 2014, 11:42

Re: Увеличить производительность многопоточностью

Сообщение Viewer » 19 авг 2014, 13:40

Т.е. вы тоже утверждаете, что два потока в пределах одного процесса распараллеливаться на двух разных ядрах не будут?

Аватара пользователя
altwin
Сообщения: 1951
Зарегистрирован: 13 ноя 2013, 14:46

Re: Увеличить производительность многопоточностью

Сообщение altwin » 19 авг 2014, 13:45

Viewer писал(а):Т.е. вы тоже утверждаете, что два потока в пределах одного процесса распараллеливаться на двух разных ядрах не будут?
так это в принципе не возможно не только в android но и в любой другой системе. естественно, если запускаются потоки внутри одного процесса их не возможно разделить на ядра процессора, но для того и нужно непосредственно обращаться к pthread, чтобы запускать задачу не в отдельном потоке, а именно создавать новый процесс.
Изображение

Viewer
Сообщения: 180
Зарегистрирован: 30 апр 2014, 11:42

Re: Увеличить производительность многопоточностью

Сообщение Viewer » 19 авг 2014, 13:51

Странно, как же тогда это работает в приведенном примере, там создаются именно потоки в пределах одного процесса. Может создаются какие-то клоны процессов и физически потоки выполняются в разных процессах?

Аватара пользователя
altwin
Сообщения: 1951
Зарегистрирован: 13 ноя 2013, 14:46

Re: Увеличить производительность многопоточностью

Сообщение altwin » 19 авг 2014, 14:20

Viewer писал(а):Странно, как же тогда это работает в приведенном примере, там создаются именно потоки в пределах одного процесса. Может создаются какие-то клоны процессов и физически потоки выполняются в разных процессах?
поток и процесс -это просто термины. Когда поток создается, он привязывается к ядру, если поток рожден процессом, который уже привязан к конкретному ядру, то он физически не может выйти за пределы своего родителя. Суть именно в многозадачности, т.е. когда указывается адрес ядра, то по сути для нового потока создается процесс и они там как то привязываются к основному процессу по аналогии one-to-many возвращая потом туда результаты. Но это все уже виртуально, posix -это высокоуровневая библиотека, драйвера в ОС обеспечивают интерфейс между железом и posix функциями, по сути всего остального нет, просто создаются приоритетные очереди потоков на каждое ядро, но к примеру когда один поток в очереди(т.е. процесс) рождает внутренние потоки(тут уже рекурсия), по сути мы получаем вложенные очереди, это практически то, что получается, при работе с AsyncTask в android, и мы не можем из вложенной очереди перенести задачу в очередь к другому ядру, максимум создать новую вложенную. И тут как раз нужен jni, c его помощью мы создаем не вложенную очередь для процесса нашего приложения внутри android, а именно можем "положить" свою задачу в "общую" очередь к любому ядру.

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

Viewer
Сообщения: 180
Зарегистрирован: 30 апр 2014, 11:42

Re: Увеличить производительность многопоточностью

Сообщение Viewer » 19 авг 2014, 16:14

В общем я понял так, что сама система может каким-то мистическим образом распараллеливать потоки одного процесса по разным ядрам процессора (у меня 4 потока одного процесса прекрасно распределились по всем 4-м ядрам Qualcomm Snapdragon 800), но если мы принудительно захотим сами это делать, то нам нужно их разносить по разным процессам?

Ответить