#python #memory #triangulation #pypy #voxel
#python #память #триангуляция #pypy #воксель
Вопрос:
Я работаю над вокселизацией для моделей STL на основе разреженных воксельных восьмеричных деревьев. У меня есть 3D-массив, содержащий около 100 000 треугольников (каждый имеет 3 точки со значением x, y, z для каждой точки).
Мне нужно вычислить несколько точек и значений для каждого треугольника. Я написал этот алгоритм в стандартном CPython, и для запуска потребовалось 3 секунды, что для меня было слишком медленно (около 0,5 с было бы неплохо).
Я переключился на PyPy в качестве JIT-компилятора, и он работал очень хорошо. Если я запускаю код без набора A точек / значений (см. Код) для каждого треугольника (вычисляю ограничивающую рамку и нормаль), он превосходит CPython в 10 и более раз, и если я запускаю код без набора B точек, он также превосходит CPython. В тот момент, когда я запускаю алгоритм с обоими наборами, он работает намного медленнее, чем CPython (или Set A solo Set B solo вместе взятые).
Вы хоть представляете, в чем проблема прямо здесь? Я думал, что это может быть проблема с памятью. Я назначил больше памяти кучи для pypy в параметрах виртуальной машины, не сработало. Я удалил все переменные после того, как итерация цикла (с «del») не сработала.
Я использую Windows 10 Home версии 10.0.18363 на компьютере с ОС x64.
Я использую pypy3.6-v7.3.2rc1-win32 в PyCharm Community Edition 2020.2.2
Это параметры виртуальной машины:
-Xmx2048m
-Xms750m
-XX:ReservedCodeCacheSize=240m
-XX: UseConcMarkSweepGC
-XX:SoftRefLRUPolicyMSPerMB=50
-ea
-XX:CICompilerCount=2
-Dsun.io.useCanonPrefixCache=false
-Djdk.http.auth.tunneling.disabledSchemes=""
-XX: HeapDumpOnOutOfMemoryError
-XX:-OmitStackTraceInFastThrow
-Djdk.attach.allowAttachSelf=true
-Dkotlinx.coroutines.debug=off
-Djdk.module.illegalAccess.silent=true
Большое вам спасибо за каждое предложение.
import trimesh as tr
import sys
import datetime
def doT(a,b):
res=a[0]*b[0] a[1]*b[1] a[2]*b[2]
return res
def doT2(a,b):
res=a[0]*b[0] a[1]*b[1]
return res
def minus (a,b):
res=[a[0]-b[0],a[1]-b[1],a[2]-b[2]]
return res
def plus (a,b):
res = [a[0] b[0], a[1] b[1], a[2] b[2]]
return res
def crosS(a,b):
res=[a[1]*b[2]-a[2]*b[1],a[2]*b[0]-a[0]*b[2],a[0]*b[1]-a[1]-b[0]]
return res
def miN(a,b):
if a<b:
return a
else:
return b
def maX(a,b):
if a>b:
return a
else:
return b
trim=tr.load("Stanford_Bunny.stl")
trim.rezero()
triangle_list_tr=trim.triangles
triangle_list=triangle_list_tr.tolist()
for triangle in triangle_list:
'vertices of surface triangle'
P1 = triangle[0]
P2 = triangle[1]
P3 = triangle[2]
n = crosS(minus(P1, P2), minus(P3, P2))
n_sum = n[0] n[1] n[2]
n[0] = n[0] / abs(n_sum)
n[1] = n[1] / abs(n_sum)
n[2] = n[2] / abs(n_sum)
P1x = triangle[0][0]
P1y = triangle[0][1]
P1z = triangle[0][2]
P2x = triangle[1][0]
P2y = triangle[1][1]
P2z = triangle[1][2]
P3x = triangle[2][0]
P3y = triangle[2][1]
P3z = triangle[2][2]
counter =1
#Set A start
bbxmin = min(P1x, P2x, P3x)
bbxmax = max(P1x, P2x, P3x)
bbymin = min(P1y, P2y, P3y)
bbymax = max(P1y, P2y, P3y)
bbzmin = min(P1z, P2z, P3z)
bbzmax = max(P1z, P2z, P3z)
#Set A End
#Set B Start
P1_xy = [P1[0], P1[1]]
P2_xy = [P2[0], P2[1]]
P3_xy = [P3[0], P3[1]]
if n[2] >= 0:
e_xy_12 = [-1 * (P1[1] - P2[1]), P1[0] - P2[0]]
e_xy_23 = [-1 * (P2[1] - P3[1]), P2[0] - P3[0]]
e_xy_31 = [-1 * (P3[1] - P1[1]), P3[0] - P1[0]]
else:
e_xy_12 = [-1 * (P2[1] - P1[1]), P2[0] - P1[0]]
e_xy_23 = [-1 * (P3[1] - P2[1]), P3[0] - P2[0]]
e_xy_31 = [-1 * (P1[1] - P3[1]), P1[0] - P3[0]]
P1_xz = [P1[0], P1[2]]
P2_xz = [P2[0], P2[2]]
P3_xz = [P3[0], P3[2]]
if n[1] >= 0:
e_xz_12 = [-1 * (P2[2] - P1[2]), P2[0] - P1[0]]
e_xz_23 = [-1 * (P3[2] - P2[2]), P3[0] - P2[0]]
e_xz_31 = [-1 * (P1[2] - P3[2]), P1[0] - P3[0]]
else:
e_xz_12 = [-1 * (P1[2] - P2[2]), P1[0] - P2[0]]
e_xz_23 = [-1 * (P2[2] - P3[2]), P2[0] - P3[0]]
e_xz_31 = [-1 * (P3[2] - P1[2]), P3[0] - P1[0]]
P1_yz = [P1[1], P1[2]]
P2_yz = [P2[1], P2[2]]
P3_yz = [P3[1], P3[2]]
if n[0] >= 0:
e_yz_12 = [-1 * (P1[2] - P2[2]), P1[1] - P2[1]]
e_yz_23 = [-1 * (P2[2] - P3[2]), P2[1] - P3[1]]
e_yz_31 = [-1 * (P3[2] - P1[2]), P3[1] - P1[1]]
else:
e_yz_12 = [-1 * (P2[2] - P1[2]), P2[1] - P1[1]]
e_yz_23 = [-1 * (P3[2] - P2[2]), P3[1] - P2[1]]
e_yz_31 = [-1 * (P1[2] - P3[2]), P1[1] - P3[1]]
#Set B End
del bbxmin
del bbxmax
del bbymin
del bbymax
del bbzmin
del bbzmax
del P1x
del P1y
del P1z
del P2x
del P2y
del P2z
del P3x
del P3y
del P3z
del P1_xy
del P2_xy
del P3_xy
del P1_xz
del P2_xz
del P3_xz
del P1_yz
del P2_yz
del P3_yz
del P1
del P2
del P3
del e_yz_12
del e_yz_23
del e_yz_31
del e_xz_12
del e_xz_23
del e_xz_31
del e_xy_12
del e_xy_23
del e_xy_31
Комментарии:
1. Я вижу, вы импортируете numpy. Это будет выполняться медленно в PyPy, поскольку оно написано с интенсивным использованием Python C-API. Возможно,
trimesh
также использует C-API, я с ним не знаком.2. Спасибо вам за ваш ответ. Я знаю, что numpy и другие пакеты на основе C-APi замедлят производительность pypy. Я использую trimesh для импорта файла STL. Описанные различия в производительности появляются в другой части программы, но вы правы в том, что aorund trimesh был бы идеальным. Numpy больше не используется (за исключением части trimesh), и импорт — это просто остаток от более старой версии. Я отредактирую сообщение соответствующим образом и удалю импорт.
Ответ №1:
Pypy работает медленнее, если в коде много вложенных if else. CPython уже намного более оптимизирован для if else. Если вы используете python надлежащим образом (не так, как C), тогда pypy будет быстрее.