Форум программистов, компьютерный форум, киберфорум
Python для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.71/7: Рейтинг темы: голосов - 7, средняя оценка - 4.71
6 / 5 / 2
Регистрация: 04.01.2013
Сообщений: 56

Время расчета на нескольких процессорах в 30-40 раз больше чем на одном

27.04.2015, 15:37. Показов 1584. Ответов 12
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Нужно написать программу для параллельных вычислений на нескольких процессорах. На одном считает очень долго.

Начал с простого примера взятого из интернета и переделанного под себя.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# -*- coding: utf-8 -*-
import time
import ctypes
import multiprocessing as mp
import numpy as np
import math
 
def getL(p1, p2):
    u""" Расстояние между 2-мя точками
    """
    return math.sqrt((p1[0]-p2[0])**2+(p1[1]-p2[1])**2)
 
def generateField(w, h):
    u""" Генерируем массив
    """
    field = []
    for x in xrange(w):
        field.append([])
        for y in xrange(h):
            field[x].append(0)
    return field
 
def spCalcFn(field, p):
    u""" Расчет на одном процессоре
    """
    xP = p[0]
    yP = p[1]
    w = len(field)
    h = len(field[0])
    ## для каждой точки определяем расстояние до расчетной точки p
    for x in xrange(w):
        for y in xrange(h):
            field[x][y] = getL(p, (x,y))
    return field
 
def mpCalcFn_Worker(field, queue, memory, p):
    u""" Worker process для расчета на нескольких процессорах
    """
    xP = p[0]
    yP = p[1]
    
    w = len(field)      # ширина 
    h = len(field[0])   # высота
 
    ## область общей памяти
    fieldResult = np.reshape(np.frombuffer(memory), (w, h))
 
    while True:
        ## получаем задание (начальная строка, кол-во строк)
        job = queue.get()
        if job == None:
            break
 
        ## начальная строка
        start = job[0]
        ## конечная строка
        stop = job[0] + job[1]
        
        ## для каждой точки в строках от start до stop 
        ## определяем расстояние до расчетной точки p
        for x in xrange(start, stop):
            for y in xrange(h):
                fieldResult[x][y] = getL(p, (x,y))
        queue.task_done()
    queue.task_done()
 
def mpCalcFn(field, p):
    u""" Расчет на нескольких процессорах
    """
 
    w = len(field)      # ширина 
    h = len(field[0])   # высота
    
    ## создаем область общей памяти 
    memory = mp.RawArray(ctypes.c_double, w * h)
   
    # setup jobs
#    nCPU = mp.cpu_count()    # количество процессоров
    nCPU = 4
    nJobs = nCPU
   
    q = w / nJobs  
    r = w % nJobs  
 
    jobs = []   
    firstRow = 0 
    for i in range(nJobs): 
        rowsInJob = q ## количество обрабатываем строк в одном job
        if (r > 0): # если остаток от деления больше 0
            # увеличиваем количество строк на 1
            rowsInJob += 1
            # уменьшаем остаток на 1
            r -= 1
        ## добавляем в перечень работ сведения о первой строке и количестве строк
        jobs.append((firstRow, rowsInJob)) 
        firstRow += rowsInJob 
    
    ## создаем очередь    
    queue = mp.JoinableQueue()
    ## добавляем jobs в очередь
    for job in jobs:
        queue.put(job)
    ## добавляем в конец очереди None по количеству процессоров
    for i in range(nCPU):
        queue.put(None)
 
    # run workers
    workers = []
    for i in range(nCPU):
        ## создаем процесс 
        worker = mp.Process(target = mpCalcFn_Worker,
                            args = (field, queue, memory, p))
        #№ добавляем
        workers.append(worker)
        ## запускае процесс на выполнение
        worker.start()
        
    queue.join()
   
    ## из области общей памяти создаем массив с результатами 
    fieldResult = np.reshape(np.frombuffer(memory), (w, h))
    return fieldResult
 
def main():
    u""" Сравниваем время выполнения на одном и на нескольких процессорах
    """
    ## количество процессоров
    print u"Количество процессоров: %.0f" % mp.cpu_count()
    
    ## генерируем двумерный массив
    field = generateField(2000, 800)
    ## выбираем точку для расчета
    p = (100, 100)
    
    ## расчет на одном процессоре    
    t0 = time.time()
    spField = spCalcFn(field, p)
    t1 = time.time()
    print u"Один процессор: %.3f сек." % (t1 - t0)
 
    ## расчет на нескольких процессорах
    t0 = time.time()
    mpField = mpCalcFn(field, p)
    t1 = time.time()
    print u"Несколько процессоров: %.3f сек." % (t1 - t0)
 
if __name__ == '__main__':
    main()

В результате время выполнения на 4-8 процессорах в 40-60 раз дольше чем на одном.

Подскажите в чем проблема?
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
27.04.2015, 15:37
Ответы с готовыми решениями:

MPI: программа на нескольких процессорах работает не как на одном
Написал программу с MPI для обработки изображений. С одним процессором работает правильно. Но когда запускаю с несколькими, то...

Функция: Написать функцию next(t, t1, d), которая присваивает параметру t1 время на d секунд больше, чем время t.
Прошу помочь. Ввести структуру time с полями часы, минуты, секунды. Составить и протестировать функции: next(t, t1, d), которая...

Монета брошена 800 раз. Найти вероятность того, что «герб» выпадет на 20 раз больше, чем решка
Решите пожалуйста)

12
Эксперт Python
 Аватар для dondublon
4652 / 2072 / 366
Регистрация: 17.03.2012
Сообщений: 10,182
Записей в блоге: 6
27.04.2015, 16:22
Попробуйте области памяти создать свою для каждого потока, а не одну на всех.
А вообще, для быстрой работы с числами лучше использовать numpy.
0
6 / 5 / 2
Регистрация: 04.01.2013
Сообщений: 56
27.04.2015, 18:13  [ТС]
Область памяти должна быть общей, потому что для каждой точки рисунка (двумерный массив) нужно произвести отдельные вычисления от нескольких выделенных точек и результата для данной точки суммировать.

numpy навряд ли поможет, потому что нужно делать кучу специфических вычислений
0
2742 / 2341 / 620
Регистрация: 19.03.2012
Сообщений: 8,830
27.04.2015, 18:40
hexadecimal, Ты не прав, все вычисления такого рода нужно сделать через numpy и подобные библиотеки.
Посмотри вот это видео, там много полезной инфы https://moscowdjango.ru/meetup... ython-why/ + почитай стати на которые он ссылается.

Добавлено через 1 минуту
hexadecimal, Кстати стоит заметить, что все библиотеки связанные с научными вычислениями или графикой используют numpy и подобные. Посмотри на пример на matplotlib.
0
Эксперт Python
 Аватар для dondublon
4652 / 2072 / 366
Регистрация: 17.03.2012
Сообщений: 10,182
Записей в блоге: 6
28.04.2015, 07:30
Цитата Сообщение от hexadecimal Посмотреть сообщение
Область памяти должна быть общей, потому что для каждой точки рисунка (двумерный массив) нужно произвести отдельные вычисления от нескольких выделенных точек и результата для данной точки суммировать.
Не очень понял сказанное, но, если для каждой точки обработка в потоке зависит от других потоков - распараллелить задачу невозможно, не так ли?
Создание своих копий областей памяти должно сработать в силу того, что задачу распараллелить возможно. А смысл - в более эффективном использовании кэша процессора L3, есть такой нюанс.

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

Цитата Сообщение от hexadecimal Посмотреть сообщение
нужно делать кучу специфических вычислений
Пока что не заметил ничего специфического. Можете написать, что не получается сделать на numpy - авось, поможем. Затем и форум.
0
6 / 5 / 2
Регистрация: 04.01.2013
Сообщений: 56
28.04.2015, 09:48  [ТС]
dondublon, попробую объяснить.
Есть изображение (карта), на ней выделены сколько-то точечных объектов (objs = [obj1, obj2, ...]).
Для каждого объекта (obj) просчитаны несколько различных вариантов сценариев (scripts = [script1, script2, ....]).
Для каждого сценария получен массив некоторых значений (resultArr = [100,90,80, ..., 0]), которые зависят от расстояния.

Сначала создаем массив (arr = [[0,0,0,...],[0,0,0,...],...]) с размерами изображения (w, h) и забиваем его нулями.

Потом для каждого точечного объекта (obj)
для каждого сценария (script)
для каждой точки на рисунке (x,y) определяем расстояние до точечного объекта.
Находим значение (val) для данного расстояния, которое мы определили ранее.
Добавляем в значение в массив arr[x][y] += val.
Поэтому и нужно чтоб массив был один
Это упрощенно. Значения могут меняться в зависимости от направления (angl = 0... 2*pi), может быть направлено только в определенную сторону (в остальные стороны = 0), объект может находится в замкнутом пространстве какой-то формы (shape = [p1, p2, p3, p4 ... p1]) и необходимо определять находится точка рисунка внутри shape или на определенном расстоянии от shape, также нужно отсекать области для сценариев (script) rect = ((Xmin,Ymin),(Xmax,Ymax)) (для одних сценариев максимальное расстояние м.б. 10 пк для других выходить за пределы изображения) и др.

Для нескольких точечных объектов (5-10-20) расчет происходит быстро.
Проблемы возникают для линейных объектов особенно протяженных на больших изображениях. Эти объекты мы делим на участки (попиксельно) и получаем сотни и тысячи точечных объектов. В этом случае расчет занимает уже десятки минут или несколько часов.

Для сокращения времени этого расчета и нужно распараллелить вычисления. Например, по объектам или по строкам.

Попробую вечером накидать пример.
0
Эксперт Python
 Аватар для dondublon
4652 / 2072 / 366
Регистрация: 17.03.2012
Сообщений: 10,182
Записей в блоге: 6
28.04.2015, 11:29
hexadecimal, и всё-таки - не вижу у вас ничего специфичного. Сплошная арифметика. numpy c этим справляется на ура. Главная сложность - в формировании массивов.
Например, я у вас вижу вычисление расстояния в цикле, многократно повторяется. Питоновские циклы - медленные. Начать переписывать можно с этого.

Добавлено через 14 минут
Например, вот этот кусок:
Цитата Сообщение от hexadecimal Посмотреть сообщение
for x in xrange(start, stop):
* * * * * * for y in xrange(h):
* * * * * * * * fieldResult[x][y] = getL(p, (x,y))
я бы переписал так:
Python
1
2
3
x, y = np.meshgrid(np.arange(start, stop), np.arange(h))
# p == (p[0], p[1])
fieldResult = np.sqrt(np.power(x - p[0], 2) + np.power(y - p[1], 2))
Добавлено через 1 час 11 минут
Да, чё-та я не подумал. Так неоптимально, много повторяющихся вычислений. Но я показал общее направление, если интересно - спрашивайте.
0
6 / 5 / 2
Регистрация: 04.01.2013
Сообщений: 56
04.05.2015, 22:23  [ТС]
Дошли, наконец-то, руки написать скрипт. Вот что получилось (см. аттач).

На Win7 x86 на 2-х процессорах считает немного быстрее чем на одном (примерно 3 мин вместо 4).
На Win7 x64 выдает ошибку
" File "....\Python\27\lib\pickle.py", line 748, in save_global
(obj, module, name))
pickle.PicklingError: Can't pickle <type 'ImagingCore'>: it's not found as __builtin__.ImagingCore"


dondublon, для nampy здесь слишком много логики (принадлежность многоугольнику, расстояние до многоугольника, направление). Не совсем представляю как его применить для данного случая
Вложения
Тип файла: zip test_draw.zip (9.3 Кб, 0 просмотров)
0
Эксперт Python
 Аватар для dondublon
4652 / 2072 / 366
Регистрация: 17.03.2012
Сообщений: 10,182
Записей в блоге: 6
05.05.2015, 07:58
Функция принадлежности точки многоугольнику, на numpy.
Давно собирался написать для себя, кстати, да всё руки не доходили. Вот, подвернулся случай
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import numpy as np
 
def point_in_contour(p, x0, y0):
    x1 = np.roll(x0, 1)
    y1 = np.roll(y0, 1)
    in_trap_x = np.logical_or(np.logical_and(x0 <= p[0], p[0] < x1), np.logical_and(x1 <= p[0], p[0] < x0))
    x0_, y0_, x1_, y1_ = [arr[in_trap_x] for arr in x0, y0, x1, y1]
    k = (y1_ - y0_) / (x1_ - x0_)
    ly = y0_ + k * (p[0] - x0_)
    gr = ly > p[1]  # or >=
    if gr.size == 0:
        result = False
    else:
        result = np.logical_xor.reduce(gr)
    return result
Python
1
2
3
4
x = np.array([1, 0, 1, 3, 4, 3])
y = np.array([0, 2, 4, 4, 2, 0])
    
print point_in_contour((0.5, 1.), x, y)
2
2838 / 1647 / 254
Регистрация: 03.12.2007
Сообщений: 4,222
05.05.2015, 18:21
dondublon, в 8 строке целочисленное деление при целочисленных координатах и потенциальное деление на 0.

Добавлено через 15 минут
И ещё, кажется, если попадётся точка с x = p[0], можно получить сюрприз.
0
Эксперт Python
 Аватар для dondublon
4652 / 2072 / 366
Регистрация: 17.03.2012
Сообщений: 10,182
Записей в блоге: 6
05.05.2015, 20:58
Насчёт строки 8 - ну так не надо держать координаты целыми. А деления на 0 там не будет, потому что в строке 6 так сформирован массив. Если x1==x0, то этот отрезок не попадёт в in_trap_x.
Если x==p[0], то всё нормально, там просто 0 будет.
1
2838 / 1647 / 254
Регистрация: 03.12.2007
Сообщений: 4,222
06.05.2015, 18:48
Цитата Сообщение от dondublon Посмотреть сообщение
ну так не надо держать координаты целыми
Просто в приведённом примере используются целочисленные координаты... В остальном согласен.
0
Эксперт Python
 Аватар для dondublon
4652 / 2072 / 366
Регистрация: 17.03.2012
Сообщений: 10,182
Записей в блоге: 6
06.05.2015, 22:11
Somebody, так уж вышло
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
06.05.2015, 22:11
Помогаю со студенческими работами здесь

В чем смысл нескольких проектов в одном решении?
Дает ли это хоть какие-то преимущества?

На нескольких ПК - браузер Google Chrome везде-на одном ПК через время перестают загружаться Яндекс Картинки
Здравствуйте проблема windows7-32 на нескольких ПК - браузер Google Chrome везде- на одном из ПК в браузере Google Chrome - через время...

Работа Java на нескольких процессорах
Доброго времени суток!!! Вопрос следующего характера. Имеем Java приложение. Нейронная сеть, которая обрабатывает файл с данными. При...

Вычесть два массива, если в одном массиве больше элементов, чем в другом
Здраствуйте! Сижу изучаю одномерные массивы, но зашел в тупик на счет вычитания массивов... Для вас это конечно просто, но я чего-то не...

Множество: напечатать все звонкие согласные, которые есть в больше чем в одном слове
Используя множество Pascal : Задано непустую последовательность слов в строчке, между словами &quot;,&quot; в конце строчки &quot;.&quot; ,...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
13
Ответ Создать тему
Новые блоги и статьи
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
SDL3 для Android: Загрузка PNG с альфа-каналом с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
SDL3 для Android: Загрузка PNG с альфа-каналом с помощью SDL3_image
8Observer8 27.01.2026
Содержание блога SDL3_image - это библиотека для загрузки и работы с изображениями. Эта пошаговая инструкция покажет, как загрузить и вывести на экран смартфона картинку с альфа-каналом, то есть с. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru