Многоядерное программирование - PullRequest
0 голосов
/ 25 мая 2020

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

Я хочу знать, возможно ли это:
У меня есть определенная функция, которая будет повторяться 3 раза для 3 разных переменных. Можно ли запустить 3 одновременно в разные ядра (потому что им не нужна информация друг о друге)? Поскольку процесс расчета одинаков для всех из них, и вместо того, чтобы запускать одну переменную за раз, я хотел бы запустить все 3 сразу (выполняя все вычисления одновременно) и в конце концов вернуть результаты.

Некоторая часть того, что я хотел бы оптимизировать:

for v in [obj2_v1, obj2_v2, obj2_v3]:
    distancia_final_v,       \
    pontos_intersecao_final_v = calculo_vertice( obj1_normal,
                                                 obj1_v1,
                                                 obj1_v2,
                                                 obj1_v3,
                                                 obj2_normal,
                                                 v,
                                                 criterio
                                                 )

def calculo_vertice( obj1_normal,
                     obj1_v1,
                     obj1_v2,
                     obj1_v3,
                     obj2_normal,
                     obj2_v,
                     criterio
                     ):
    i = 0
    distancia_final_v = []
    pontos_intersecao_final_v = []

    while i < len(obj2_v):

        distancia_relevante_v = []
        pontos_intersecao_v   = []
        distancia_inicial     = 1000

        for x in range(len(obj1_v1)):

            planeNormal = np.array( [obj1_normal[x][0],
                                     obj1_normal[x][1],
                                     obj1_normal[x][2]
                                     ] )
            planePoint  = np.array( [    obj1_v1[x][0],
                                         obj1_v1[x][1],
                                         obj1_v1[x][2]
                                         ] )          # Any point on the plane
            rayDirection = np.array([obj2_normal[i][0],
                                     obj2_normal[i][1],
                                     obj2_normal[i][2]
                                     ] )              # Define a ray
            rayPoint     = np.array([     obj2_v[i][0],
                                          obj2_v[i][1],
                                          obj2_v[i][2]
                                          ] )         # Any point along the ray

            Psi = Calculos.line_plane_collision( planeNormal,
                                                 planePoint,
                                                 rayDirection,
                                                 rayPoint
                                                 )

            a   = Calculos.area_trianglo_3d( obj1_v1[x][0],
                                             obj1_v1[x][1],
                                             obj1_v1[x][2],
                                             obj1_v2[x][0],
                                             obj1_v2[x][1],
                                             obj1_v2[x][2],
                                             obj1_v3[x][0],
                                             obj1_v3[x][1],
                                             obj1_v3[x][2]
                                             )
            b   = Calculos.area_trianglo_3d( obj1_v1[x][0],
                                             obj1_v1[x][1],
                                             obj1_v1[x][2],
                                             obj1_v2[x][0],
                                             obj1_v2[x][1],
                                             obj1_v2[x][2],
                                             Psi[0][0],
                                             Psi[0][1],
                                             Psi[0][2]
                                             )
            c   = Calculos.area_trianglo_3d( obj1_v1[x][0],
                                             obj1_v1[x][1],
                                             obj1_v1[x][2], 
                                             obj1_v3[x][0],
                                             obj1_v3[x][1],
                                             obj1_v3[x][2],
                                             Psi[0][0],
                                             Psi[0][1],
                                             Psi[0][2]
                                             )
            d   = Calculos.area_trianglo_3d( obj1_v2[x][0],
                                             obj1_v2[x][1],
                                             obj1_v2[x][2],
                                             obj1_v3[x][0],
                                             obj1_v3[x][1],
                                             obj1_v3[x][2],
                                             Psi[0][0],
                                             Psi[0][1],
                                             Psi[0][2]
                                             )

            if float("{:.5f}".format(a)) == float("{:.5f}".format(b + c + d)):

                P1 = Ponto(    Psi[0][0],    Psi[0][1],    Psi[0][2] )
                P2 = Ponto( obj2_v[i][0], obj2_v[i][1], obj2_v[i][2] )

                distancia = Calculos.distancia_pontos( P1, P2 ) * 10

                if distancia < distancia_inicial and distancia < criterio:
                    distancia_inicial     = distancia
                    distancia_relevante_v = []
                    distancia_relevante_v.append( distancia_inicial )
                    pontos_intersecao_v   = []
                    pontos_intersecao_v.append( Psi )

            x += 1

        distancia_final_v.append( distancia_relevante_v )
        pontos_intersecao_final_v.append( pontos_intersecao_v )

        i += 1

    return distancia_final_v, pontos_intersecao_final_v

В этом примере моего кода я хочу сделать тот же процесс для obj2_v1, obj2_v2, obj2_v3.

Is возможно ли сделать это одновременно?

Потому что я буду использовать значительный объем данных , и это, вероятно, сэкономит мне время обработки.

Ответы [ 3 ]

0 голосов
/ 25 мая 2020

multiprocessing (с использованием процессов, чтобы избежать GIL) является самым простым, но вы ограничены относительно небольшими улучшениями производительности, ограничение на количество ядер - это ограничение, см. закон Амдала . есть также небольшая задержка, связанная с запуском / остановкой работы, что означает, что это намного лучше для вещей, которые занимают> 10 мс

в numeri c тяжелом коде (как это кажется), вы действительно хотите двигаться как большая часть этого "внутри numpy", посмотрите на векторизацию и трансляцию . это может дать ускорение> 50x (только на одном ядре), оставаясь при этом более простым для понимания и рассуждать о

, если ваш алгоритм трудно express с использованием numpy встроенных функций, тогда вы также можете посмотреть на использование Cython . это позволяет вам писать код Python, который автоматически компилируется до C и, следовательно, намного быстрее. В 50 раз быстрее, вероятно, также является разумным ускорением, и это все еще работает на одном ядре

методы numpy и Cython могут быть объединены с multiprocessing (то есть с использованием нескольких ядер) для получения кода, который запускает сотни в разы быстрее, чем наивные реализации.

Ноутбуки Jupyter имеют дружественные расширения (ласково известные как «magi c»), которые упрощают начало работы с такого рода производительностью. специальный %timeit позволяет вам легко синхронизировать части кода, а расширение Cython означает, что вы можете поместить все в один файл

0 голосов
/ 25 мая 2020

Q : «Возможно ли , чтобы они происходили одновременно?»

Да .

Наилучшие результаты когда-либо будут получены, если не добавить никакого python (модуль multiprocessing вообще не нужен для создания 3 полных копий (да, сверху вниз полностью реплицированные копии) процесса __main__ python для этой столь неловко независимой обработки).

Причины этого подробно объясняются здесь и здесь .

Достаточно инструмента GNU:
$ parallel --jobs 3 python job-script.py {} ::: "v1" "v2" "v3"

Для всех настроек производительности читайте подробности конфигурации в man parallel.


«Поскольку я буду использовать значительный объем данных ...»

enter image description here

Дьявол скрыт в деталях:

Код O / P может синтаксически приводить интерпретатор python к результатам, точным (приблизительным) в пределах 5 десятичные знаки, да Основной грех состоит в том, что в конечном итоге это плохие шансы продемонстрировать какую-либо разумно достижимую производительность при этом, хуже всего на «значительном объеме данных» .

Если они, «в компании» , ожидайте некоторых «значительного количества данных» , вам следует провести хотя бы элементарное исследование того, что такое обработка, направленная на.

Худшая часть (не говоря уже о разложении однажды векторизованных numpy -массивов обратно в atomi c "плавающие" значения координат) - это point-inside-triangle тест.

Для краткого анализа того, как ускорить эту часть (тем более, если собираетесь залить «значительное количество данных» при выполнении этого), вдохновляйтесь этим сообщением и выполняйте работу за меньшее время, чем было написано в O / P выше.

Косвенное тестирование точки -inside-треугольник путем сравнения неравенства пары re- float() -ed- string s, полученных fr сумма площадей треугольника ( b + c + d ) - это лишь один из ограничителей производительности, который вам нужно удалить.

0 голосов
/ 25 мая 2020

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

ОБНОВЛЕНИЕ

НЕ сделайте что-нибудь подобное (спасибо за @ user3666197 за указание на ошибку):

from multiprocessing.pool import ThreadPool

def calculo_vertice(obj1_normal,obj1_v1,obj1_v2,obj1_v3,obj2_normal,obj2_v,criterio):
      #your code
      return distancia_final_v,pontos_intersecao_final_v

pool = ThreadPool(processes=3)
async_result1 = pool.apply_async(calculo_vertice, (#your args here))
async_result2 = pool.apply_async(calculo_vertice, (#your args here))
async_result3 = pool.apply_async(calculo_vertice, (#your args here))  

result1 = async_result1.get()  # result1
result2 = async_result2.get()  # result2
result3 = async_result3.get()  # result3

Вместо этого что-то вроде этого должно сработать:

from multiprocessing import Process, Pipe

def calculo_vertice(obj1_normal,obj1_v1,obj1_v2,obj1_v3,obj2_normal,obj2_v,criterio, send_end):
      #your code
      send_end.send((distancia_final_v,pontos_intersecao_final_v))

numberOfWorkers = 3
jobs = []
pipeList = []

#Start process and build job list
for i in range(numberOfWorkers):
    recv_end, send_end = Pipe(False)
    process = Process(target=calculo_vertice, args=(#<... your args...>#, send_end))
    jobs.append(process)
    pipeList.append(recv_end)
    process.start()

#Show the results
for job in jobs: job.join()
resultList = [x.recv() for x in pipeList]
print (resultList)

REF.

https://docs.python.org/3/library/multiprocessing.html { ссылка }

Этот код создаст пул из 3 рабочих процессов, и каждый из них будет асинхронно c получать функцию . Важно отметить, что в этом случае у вас должно быть 3+ ядра ЦП, иначе ядро ​​вашей системы будет просто переключаться между процессами, и что-то не будет работать параллельно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...