параллельность + синхронизации (примеры)

Вопросы написания собственного программного кода (на любых языках)

Модератор: Olej

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: параллельность + синхронизации (примеры)

Непрочитанное сообщение Olej » 14 дек 2014, 20:34

Olej писал(а): Это сделано, пока, специально на fork(), так что под Windows такое не покатит ;-)
Родительский процесс синхронизирует порождённые по времени ("пора заканчивать") сигналом UNIX SIGUSR1, а данные обратно возвращаются через массив в shared memory.
Ну а теперь - параллельные процессы, но реализуемые пакетом multiprocessing в виде класса Process.
Это сработает в любой OS.
Меня просто удивляет, насколько изощрённо реализован пакет multiprocessing в Python ;-) ... хоть в общих чертах и понятно что и как они делают (при отсутствии клонирования fork() во всём, что a'la Windows!): запускают как клон уже загруженную копию Python с выполняющимся приложением ... но сделано это мастерски.

Код: Выделить всё

#!/usr/bin/python
# -*- coding: utf-8 -*-
import os
import time
import sys
import signal
import math
import multiprocessing
# параллельные процессы - все OS:

def handler( signum, frame ):                         # обработчик SIGUSR1
    global finish
    finish = True

def RunCounter( arr, num ) :
    global finish
    signal.signal( signal.SIGUSR1, handler )
    counter = 0
    while not finish : counter += 1
    arr[ num ] = counter

if __name__ == '__main__' :                           # для работы в Windows
    multiprocessing.freeze_support()
    nthr = 2                                          # число процессов
    sec = 1                                           # интервал выполнения
    debug = False
    finish = False                                    # флаг завергшения
    try :
        if len( sys.argv ) > 1 :
            nthr = int( sys.argv[ 1 ] )
            if len( sys.argv ) > 2 :
                sec = int( sys.argv[ 2 ] )
                if sec < 0 :                          # признак отладочной диагностики
                    sec = -sec
                    debug = True
    except ValueError :
        print( 'запуск: python[3] {} [потоков] [[-]секунд]'.format( sys.argv[ 0 ] ) )
        sys.exit( 1 )
    if( debug ) :
        print( 'число процессов {}'.format( nthr ) )
        print( 'число доступных процессоров {}'.format( multiprocessing.cpu_count() ) )
    counter = 0
    childs = [] 
    res = multiprocessing.Array( 'i', range( nthr ) ) # массив результатов в shared memory
    for i in range( nthr ) :                          # создание и запуск процессов
        p = multiprocessing.Process( target=RunCounter, args=( res, i ) )
        childs.append( p )
        p.start()
    time.sleep( sec )
    for p in childs : os.kill( p.pid, signal.SIGUSR1 )
    for p in childs : p.join()
    if debug :
        msg = ''
        for i in range( len( res ) ) : msg += '{} '.format( res[ i ] )
        print( '{}'.format( msg ) )
    sum1, sum2, sq, md = 0.0, 0.0, 0.0, 0.0           # сбор статистики
    for i in range( len( res ) ) :
        md = float( res[ i ] )
        sum1 += md
        sum2 += md * md;
    md = sum1 / nthr;                                 # среднее
    sq = math.sqrt( sum2 / nthr - md * md );          # СКО
    print( 'операций {:.0f} : {} * {:.0f} [+/-{:.2f}%]'
           .format( sum1 , nthr, md, 100. * sq / md ) )
    sys.exit( 0 )

Код: Выделить всё

[Olej@modules SpeedThread.6]$ ./PymSpeed.py 1 3
операций 62905291 : 1 * 62905291 [+/-0.00%]
[Olej@modules SpeedThread.6]$ ./PymSpeed.py 2 3
операций 113488958 : 2 * 56744479 [+/-0.05%]
[Olej@modules SpeedThread.6]$ ./PymSpeed.py 3 3
операций 147101944 : 3 * 49033981 [+/-9.55%]
[Olej@modules SpeedThread.6]$ ./PymSpeed.py 4 3
операций 164361496 : 4 * 41090374 [+/-2.41%]
[Olej@modules SpeedThread.6]$ ./PymSpeed.py 5 3
операций 175403773 : 5 * 35080755 [+/-2.18%]
[Olej@modules SpeedThread.6]$ ./PymSpeed.py 10 3
операций 167149453 : 10 * 16714945 [+/-2.94%]
[Olej@modules SpeedThread.6]$ ./PymSpeed.py 50 3
операций 187893503 : 50 * 3757870 [+/-5.40%]
Вложения
PymSpeed.py
(2.6 КБ) 417 скачиваний

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: параллельность + синхронизации (примеры)

Непрочитанное сообщение Olej » 15 дек 2014, 01:23

Olej писал(а): Ну а теперь - параллельные процессы, но реализуемые пакетом multiprocessing в виде класса Process.
Это сработает в любой OS.
Меня просто удивляет, насколько изощрённо реализован пакет multiprocessing в Python ;-) ... хоть в общих чертах и понятно что и как они делают (при отсутствии клонирования fork() во всём, что a'la Windows!): запускают как клон уже загруженную копию Python с выполняющимся приложением ... но сделано это мастерски.
И последний (на сегодня) вариант Python & multiprocessing - динамический Pool процессов:

Код: Выделить всё

#!/usr/bin/python
# -*- coding: utf-8 -*-
import os
import time
import sys
import signal
import math
import multiprocessing
# параллельные процессы - динамический пул потоков:

def RunCounter( arg ) :
    def handler( signum, frame ):                     # обработчик SIGUSR1
        global finish
        finish = True
    global finish
    finish = False                                    # флаг завергшения
    signal.signal( signal.SIGUSR1, handler )
    counter = 0
    while not finish : counter += 1
    return counter

if __name__ == '__main__' :                           # для работы в Windows
    multiprocessing.freeze_support()
    nthr = 2                                          # число процессов
    sec = 1                                           # интервал выполнения
    debug = False
    finish = False                                    # флаг завергшения
    try :
        if len( sys.argv ) > 1 :
            nthr = int( sys.argv[ 1 ] )
            if len( sys.argv ) > 2 :
                sec = int( sys.argv[ 2 ] )
                if sec < 0 :                          # признак отладочной диагностики
                    sec = -sec
                    debug = True
    except ValueError :
        print( 'запуск: python[3] {} [потоков] [[-]секунд]'.format( sys.argv[ 0 ] ) )
        sys.exit( 1 )
    if( debug ) :
        print( 'число процессов {}'.format( nthr ) )
        print( 'число доступных процессоров {}'.format( multiprocessing.cpu_count() ) )
    counter = 0
    signal.signal( signal.SIGUSR1, signal.SIG_IGN )
    pool = multiprocessing.Pool( processes = nthr, )
    ret = pool.map_async( RunCounter, [ None ] * nthr )
    time.sleep( sec )
    os.kill( -os.getpid(), signal.SIGUSR1 )
    pool.close()
    ret.wait()                                        # ожидание возвратов
    res = ret.get()                                   # список возвращённых значений 
    if debug :
        msg = ''
        for i in range( len( res ) ) : msg += '{} '.format( res[ i ] )
        print( '{}'.format( msg ) )
    sum1, sum2, sq, md = 0.0, 0.0, 0.0, 0.0           # сбор статистики
    for i in range( len( res ) ) :
        md = float( res[ i ] )
        sum1 += md
        sum2 += md * md;
    md = sum1 / nthr;                                 # среднее
    sq = math.sqrt( sum2 / nthr - md * md );          # СКО
    print( 'операций {:.0f} : {} * {:.0f} [+/-{:.2f}%]'
           .format( sum1 , nthr, md, 100. * sq / md ) )
    sys.exit( 0 )
Хорошо поработали разработчики Python!
Здесь даже не нужно ничего вручную определять из IPC для возвратов результатов из дочернего процесса - всё сделано средствами multiprocessing.
Из упрощений по сравнению с предыдущими (чтоб не повторяться ;-) ):
- здесь 1 сигнал SIGUSR1 отправляется на всю группу процессов (-pid), у которых лидером является родитель...
- сам родитель запрещает себе реакцию на этот сигнал
- сигнальный обработчик "втянут" внутрь функции дочернего процесса.

Код: Выделить всё

[Olej@modules SpeedThread.6]$ python ./PympSpeed.py 1 3
операций 64086142 : 1 * 64086142 [+/-0.00%]
[Olej@modules SpeedThread.6]$ python ./PympSpeed.py 2 3
операций 119734692 : 2 * 59867346 [+/-0.25%]
[Olej@modules SpeedThread.6]$ python ./PympSpeed.py 3 3
операций 151584749 : 3 * 50528250 [+/-6.66%]
[Olej@modules SpeedThread.6]$ python ./PympSpeed.py 4 3
операций 182891204 : 4 * 45722801 [+/-2.35%]
[Olej@modules SpeedThread.6]$ python ./PympSpeed.py 5 3
операций 178256698 : 5 * 35651340 [+/-4.30%]
[Olej@modules SpeedThread.6]$ python ./PympSpeed.py 10 3
операций 176886251 : 10 * 17688625 [+/-9.33%]

Код: Выделить всё

[Olej@modules SpeedThread.6]$ python3 ./PympSpeed.py 1 3
операций 38418508 : 1 * 38418508 [+/-0.00%]
[Olej@modules SpeedThread.6]$ python3 ./PympSpeed.py 2 3
операций 66143895 : 2 * 33071948 [+/-0.20%]
[Olej@modules SpeedThread.6]$ python3 ./PympSpeed.py 3 3
операций 77451963 : 3 * 25817321 [+/-18.02%]
[Olej@modules SpeedThread.6]$ python3 ./PympSpeed.py 4 3
операций 78332696 : 4 * 19583174 [+/-4.29%]
[Olej@modules SpeedThread.6]$ python3 ./PympSpeed.py 5 3
операций 78038152 : 5 * 15607630 [+/-6.04%]
[Olej@modules SpeedThread.6]$ python3 ./PympSpeed.py 10 3
операций 76344984 : 10 * 7634498 [+/-4.57%]
Вложения
PympSpeed.py
(2.7 КБ) 397 скачиваний

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: параллельность + синхронизации (примеры)

Непрочитанное сообщение Olej » 18 дек 2014, 11:37

Olej писал(а): Лаконизм и ясность здесь в Go, конечно, потрясающие! : просто запустить фрагмент кода (даже функции не нужно специальной) на параллельное выполнение в N ветках... а при завершении каждой ветки (не важно по какому механизму) - выполнить в каждом экземпляре по 2 функции из стека завершения.
А тут как-раз появился "в тему" свежий перевод свежей статьи: Модели конкурентности в Go. Конвейеры.

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: параллельность + синхронизации (примеры)

Непрочитанное сообщение Olej » 19 дек 2014, 19:04

Снова о Go.
Здесь много непонятного:
Olej писал(а):Попалась очень интересная статья Х обсуждение в тему: Потоки в C++ против потоков в Go.
Гоурутины это не потоки а скорее смесь фиберов с пулом потоков, причём глубоко интегрированная в язык. Понятное дело что нативную реализацию потоков она будет крыть как бык овцу. Причём чем меньше в системе процессоров тем круче будет крыть ;)
По умолчанию при запуске приложение стартует главный горутин. Вы можете создать еще горутины, чтобы выполнять некие действия паралельно, но! Все горутины выполняются в одном потоке! Память процесса делится между ними, но эти потоки "легкие" и их концепция больше всего напоминает микротреды.
И оттуда есть любопытные ссылки на подобные обсуждения и сравнения.

P.S. Написано это 4 года назад, когда возрасту реализациям (совершенствованиям) Go было ~3 года (от 2007г.), а C++ - ~30 лет (от 1983г.). ;-)
Эти и многие другие рассуждения в разных местах о том, что goroutine - некоторые "микротреды", организуемые самой системой Go ... на подобии мультетаскеру CTask ещё в MS-DOS - это, как показывают эксперименты, полная херня!

Код: Выделить всё

[Olej@modules SpeedThread.6]$ ./GoSpeed_gc 4 -20
число потоков 4
процессоров в системе 4
25330564 25274655 25740935 25609646
операций 101955800 : 4 * 25488950 [+/-0.76%]

[Olej@modules SpeedThread.6]$ ps -A -L | grep GoSpeed | wc -l
11

[Olej@modules SpeedThread.6]$ ps -A -L | grep GoSpeed
 7678  7678 pts/16   00:00:00 GoSpeed_gc
 7678  7679 pts/16   00:00:00 GoSpeed_gc
 7678  7680 pts/16   00:00:00 GoSpeed_gc
 7678  7681 pts/16   00:00:08 GoSpeed_gc
 7678  7682 pts/16   00:00:08 GoSpeed_gc
 7678  7683 pts/16   00:00:08 GoSpeed_gc
 7678  7684 pts/16   00:00:08 GoSpeed_gc
 7678  7685 pts/16   00:00:04 GoSpeed_gc
 7678  7686 pts/16   00:00:08 GoSpeed_gc
 7678  7687 pts/16   00:00:05 GoSpeed_gc
 7678  7688 pts/16   00:00:08 GoSpeed_gc
Более того, при стандартных установках своего Linux (это зависит от дистрибутива и версии), вы не сможете запустить больше 1500-1600 горутин из-за ограничений OS:

Код: Выделить всё

[Olej@modules SpeedThread.6]$ ./GoSpeed 1600 1
runtime: failed to create new OS thread (have 148 already; errno=11)
fatal error: runtime.newosproc

goroutine 16 [running]:
runtime.throw(0x5443e6)
	/usr/lib/golang/src/pkg/runtime/panic.c:520 +0x69 fp=0x7f41ea8c1c40 sp=0x7f41ea8c1c28
...
Как поймать вот такой panic() из кода, добавив свой recover() - я никак пока понять не могу.

Но стоит потрюкачить с самим Linux:

Код: Выделить всё

[Olej@modules SpeedThread.6]$ ulimit -S -u
1024
[Olej@modules SpeedThread.6]$ ulimit -H -u
31384
[Olej@modules SpeedThread.6]$ ulimit -S -u 31384
[Olej@modules SpeedThread.6]$ ulimit -S -u
31384
И вот вам пожалуйста - десятки тысяч горутин:

Код: Выделить всё

[Olej@modules SpeedThread.6]$ ./GoSpeed_gc 10000 1
операций 7668595 : 10000 * 767 [+/-43.30%]
[Olej@modules SpeedThread.6]$ ./GoSpeed_gc 20000 1
операций 10608403 : 20000 * 530 [+/-91.42%]
[Olej@modules SpeedThread.6]$ ./GoSpeed_gc 30000 1
операций 9927839 : 30000 * 331 [+/-68.46%]
Вложения
GoSpeed.go
(2.6 КБ) 454 скачивания

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: параллельность + синхронизации (примеры)

Непрочитанное сообщение Olej » 21 фев 2015, 19:52

Olej писал(а):Хотя относительно Python - это известно и понятно, что происходит ... и непонятно, почему для других интерпретирующих систем это могло бы быть иначе...
Ещё раз вернулся к этим ... не сколько кодам тестов, с кодами всё в порядке ;-) , а к интерпретации результатов. Чего как-то первоначально понять не мог:

Код: Выделить всё

[Olej@modules triangle]$ cat /proc/cpuinfo | grep 'model name'
model name      : Intel(R) Core(TM) i5-3230M CPU @ 2.60GHz
model name      : Intel(R) Core(TM) i5-3230M CPU @ 2.60GHz
model name      : Intel(R) Core(TM) i5-3230M CPU @ 2.60GHz
model name      : Intel(R) Core(TM) i5-3230M CPU @ 2.60GHz

[Olej@modules SpeedThread]$ uname -a
Linux modules.localdomain 3.18.5-101.fc20.x86_64 #1 SMP Mon Feb 2 20:58:23 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
Это то, на чём будем проверять.
Теперь результаты:

Код: Выделить всё

[Olej@modules SpeedThread]$ taskset -c 0 ./CSpeed2 1 -3
число потоков 1
число доступных процессоров 1
8927879194
операций 8927879194 : 1 * 8927879194 [+/-0.00%]

[Olej@modules SpeedThread]$ taskset -c 0,1 ./CSpeed2 2 -3
число потоков 2
число доступных процессоров 2
4500846710 4482545818
операций 8983392528 : 2 * 4491696264 [+/-0.20%]

[Olej@modules SpeedThread]$ taskset -c 0,2 ./CSpeed2 2 -3
число потоков 2
число доступных процессоров 2
8603902764 8323482001
операций 16927384765 : 2 * 8463692382 [+/-1.66%]

[Olej@modules SpeedThread]$ taskset -c 0,3 ./CSpeed2 2 -3
число потоков 2
число доступных процессоров 2
8379926470 8536425630
операций 16916352100 : 2 * 8458176050 [+/-0.93%]

[Olej@modules SpeedThread]$ taskset -c 2,3 ./CSpeed2 2 -3
число потоков 2
число доступных процессоров 2
4492225283 4490732142
операций 8982957425 : 2 * 4491478712 [+/-0.02%]
:-o
Что это значит!
А это значит то, что большинство неточностей толкования выше связаны с тем, что мой i5 (вопреки клятвенным заверениям продавца :evil: ) вовсе не имеет 4-х процессоров, которые определяет и /proc/cpuinfo, а имеет здесь место 2 процессора (0 и 2), каждому из которых спарен гипертриэдинг (0->1 и 2->3), которым приписывают кой-какое повышение производительности, но в данном случае - никакое, что и видно из цифр!

И та же история для подавляющего большинства моделей процессоров линейки i5, см.: Характеристики процессоров Intel Core i5 и Сравнительная таблица характеристик процессоров (актуальные). Да и не только i5, но и с i7 та же история!

Так что впаривает нам производитель, путая результаты, давая в тех. характеристиках "Кол-во процессов" вдвое больше реального и не объясняя значение этого показателя.

Это, может, и не имеет принципиального значения ... работает себе компьютер и работает ;-) , но принципиально важно для интерпретации результатов многопоточности-многозадачности, и понимания того, что происходит в приложениях на разных языках программирования!

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: параллельность + синхронизации (примеры)

Непрочитанное сообщение Olej » 21 фев 2015, 20:04

Olej писал(а):Это, может, и не имеет принципиального значения ... работает себе компьютер и работает ;-) , но принципиально важно для интерпретации результатов многопоточности-многозадачности, и понимания того, что происходит в приложениях на разных языках программирования!
Теперь всё становится понятнее и более предсказуемо ...

- это C классика:

Код: Выделить всё

[Olej@modules SpeedThread]$ taskset -c 0 ./CSpeed2 1 -3
число потоков 1
число доступных процессоров 1
8927879194
операций 8927879194 : 1 * 8927879194 [+/-0.00%]

[Olej@modules SpeedThread]$ taskset -c 0,1 ./CSpeed2 2 -3
число потоков 2
число доступных процессоров 2
4500846710 4482545818
операций 8983392528 : 2 * 4491696264 [+/-0.20%]
Там же (в архиве) можете проверить то же и для C++.

- это Go:

Код: Выделить всё

[Olej@modules SpeedThread]$ ./GoSpeed 1 -3
число потоков 1
процессоров в системе 4/1
4211385
операций 4211385 : 1 * 4211385 [+/-0.00%]

[Olej@modules SpeedThread]$ ./GoSpeed 2 -3
число потоков 2
процессоров в системе 4/1
3567673 3568211
операций 7135884 : 2 * 3567942 [+/-0.01%]
- это Java приложение, масштабированное на 2 процессора:

Код: Выделить всё

[Olej@modules SpeedThread]$ taskset -c 0 java RunnableSpeed 1 -3
число потоков 1
1391738556
операций 1391738556 : 1 * 1391738556 [+/-0.0%]

[Olej@modules SpeedThread]$ taskset -c 0,2 java RunnableSpeed 2 -3
число потоков 2
1378576154 1364738523
операций 2743314677 : 2 * 1371657338 [+/-0.5%]
Здесь везде отчётливое масштабирование на число доступных процессоров: каждый поток выполняется на отдельном процессоре.

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: параллельность + синхронизации (примеры)

Непрочитанное сообщение Olej » 21 фев 2015, 20:15

Olej писал(а): Здесь везде отчётливое масштабирование на число доступных процессоров: каждый поток выполняется на отдельном процессоре.
Ну и с новым отчётливым пониманием происходящего, вернёмся ещё для сравнения к Python:

- низкоуровневая модель, пакет thread:

Код: Выделить всё

[Olej@modules SpeedThread]$ ./PylSpeed.py 1 -1
число потоков 1
число доступных процессоров 4
19490562
операций 19490562 : 1 * 19490562 [+/-0.00%]

[Olej@modules SpeedThread]$ ./PylSpeed.py 2 -1
число потоков 2
число доступных процессоров 4
5397051 6458913
операций 11855964 : 2 * 5927982 [+/-8.96%]

[Olej@modules SpeedThread]$ ./PylSpeed.py 3 -1
число потоков 3
число доступных процессоров 4
3271064 3303807 3795273
операций 10370144 : 3 * 3456715 [+/-6.94%]

[Olej@modules SpeedThread]$ ./PylSpeed.py 4 -1
число потоков 4
число доступных процессоров 4
2647856 2792141 2686462 2683970
операций 10810429 : 4 * 2702607 [+/-1.99%]
- высокоуровневая модель, пакет threading:

Код: Выделить всё

[Olej@modules SpeedThread]$ ./PyhSpeed.py 1 -1
число потоков 1
число доступных процессоров 4
19867679
операций 19867679 : 1 * 19867679 [+/-0.00%]

[Olej@modules SpeedThread]$ ./PyhSpeed.py 2 -1
число потоков 2
число доступных процессоров 4
3511435 8333112
операций 11844547 : 2 * 5922274 [+/-40.71%]

[Olej@modules SpeedThread]$ ./PyhSpeed.py 3 -1
число потоков 3
число доступных процессоров 4
3492829 3294042 3560424
операций 10347295 : 3 * 3449098 [+/-3.28%]

[Olej@modules SpeedThread]$ ./PyhSpeed.py 4 -1
число потоков 4
число доступных процессоров 4
2691133 2669793 2737107 2615966
операций 10713999 : 4 * 2678500 [+/-1.63%]
И там и там - одна история: чем больше потоков, тем хуже итоговый результат (все толкутся на одном процессоре).

- параллельные процессы, пакет os:

Код: Выделить всё

[Olej@modules SpeedThread]$ ./PyfSpeed.py 1 -1
число процессов 1
число доступных процессоров 4
12276071
операций 12276071 : 1 * 12276071 [+/-0.00%]

[Olej@modules SpeedThread]$ ./PyfSpeed.py 2 -1
число процессов 2
число доступных процессоров 4
11432381 12077933
операций 23510314 : 2 * 11755157 [+/-2.75%]
- параллельные процессы, пакет multiprocessing:

Код: Выделить всё

[Olej@modules SpeedThread]$ ./PymSpeed.py 1 -1
число процессов 1
число доступных процессоров 4
20086314
операций 20086314 : 1 * 20086314 [+/-0.00%]

[Olej@modules SpeedThread]$ ./PymSpeed.py 2 -1
число процессов 2
число доступных процессоров 4
19160536 19267672
операций 38428208 : 2 * 19214104 [+/-0.28%]

[Olej@modules SpeedThread]$ ./PymSpeed.py 3 -1
число процессов 3
число доступных процессоров 4
15848554 15091975 16454089
операций 47394618 : 3 * 15798206 [+/-3.53%]

[Olej@modules SpeedThread]$ ./PymSpeed.py 4 -1
число процессов 4
число доступных процессоров 4
13725638 13014846 13165744 12917087
операций 52823315 : 4 * 13205829 [+/-2.37%]
- пул параллельных процессов, пакет multiprocessing:

Код: Выделить всё

[Olej@modules SpeedThread]$ ./PympSpeed.py 1 -1
число процессов 1
число доступных процессоров 4
20092476
операций 20092476 : 1 * 20092476 [+/-0.00%]

[Olej@modules SpeedThread]$ ./PympSpeed.py 2 -1
число процессов 2
число доступных процессоров 4
19477343 19517351
операций 38994694 : 2 * 19497347 [+/-0.10%]
Вот здесь, 3 последних варианта, с процессами, всё становится намного лучше.
Вложения
SpeedThread.tgz
(10.05 КБ) 343 скачивания

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: параллельность + синхронизации (примеры)

Непрочитанное сообщение Olej » 22 фев 2015, 02:46

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

Поэтому на время отвлекаемся в этом направлении.

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: параллельность + синхронизации (примеры)

Непрочитанное сообщение Olej » 15 авг 2015, 11:27

Olej писал(а): А это значит то, что большинство неточностей толкования выше связаны с тем, что мой i5 (вопреки клятвенным заверениям продавца :evil: ) вовсе не имеет 4-х процессоров, которые определяет и /proc/cpuinfo, а имеет здесь место 2 процессора (0 и 2), каждому из которых спарен гипертриэдинг (0->1 и 2->3), которым приписывают кой-какое повышение производительности, но в данном случае - никакое, что и видно из цифр!
Для тщательного подбора конкретного процессора в последующих сборках компьютеров я стал собирать здесь в форуме справку моделям процессоров.

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: параллельность + синхронизации (примеры)

Непрочитанное сообщение Olej » 18 ноя 2015, 02:41

Вот очень хорошая задача, взята отсюда: https://toster.ru/q/267058
Формулировка там совершенно бездарная ... но вот что в итоге удалось выдавить из студента:
вот исходный текст задачи:
Напишите программу, которая создает нить. Используйте атрибуты по умолчанию.
Родительская и вновь созданная нити должны распечатать десять строк текста.
Модифицируйте программу так, чтобы вывод родительской и дочерней нитей был синхронизован:
сначала родительская нить выводила первую строку, затем дочерняя, затем родительская
вторую строку и т.д. Используйте мутексы.

Явные и неявные передачи управления между нитями (sleep(3C)/usleep(3C), sched_yield(3RT))
и холостые циклы разрешается использовать только на этапе инициализации.

Докажите, что данная задача не может быть решена с использованием двух мутексов
без использования других средств синхронизации.
Здесь самое ключевое место "холостые циклы разрешается использовать только на этапе инициализации" ... чего публикатор задачи так и не понял.

Ответить

Вернуться в «Программирование»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 2 гостя