加速嵌套if循环下的循环

Ash*_*Ash 0 python performance for-loop if-statement nested-loops

在2d平面上,有一个以(0,0)为中心的大圆,半径为.它包含约100个左右的较小圆圈,这些圆圈在父圆上随机分布,否则具有相对于原点的已知半径和位置.(有些较小的子圆可能部分或全部位于较大的子圆内.)

整个平面均匀地网格化为像素,边长为水平和垂直(沿坐标轴).像素的大小是固定的并且是先验已知的,但是远小于父圆的大小; 在父圆圈上有大约1000个特殊像素的顺序.我们给出了所有这些特殊网格(的中心)的2D笛卡尔坐标.包含这些特殊网格中的至少一个的那些子圆被命名为*特殊的"子圆圈以供以后使用.

现在,想象一下所有这个3d空间都充满了~100,000,000个粒子.我的代码尝试在每个特殊子圈内添加这些粒子.

我设法调试我的代码,但似乎当我处理如此大量的粒子时,它很慢,如下所示.我想看看我是否可以使用任何技巧来加速它至少一个数量级.

.
.
.
for x, y in zip(vals1, vals2):  # vals1, vals2 are the 2d position array of the *special* grids each with a 1d array of size ~1000
    enclosing_circles, sub_circle_catalog, some_parameter_catalog, totals = {}, [], [], {}


    for id, mass in zip(ids_data, masss_data): # These two arrays are equal in size equal to an array of size ~100,000,000
        rule1 = some_condition           # this check if each special grid is within each circle
        rule2 = some_other_condition     # this makes sure that we are only concerned with those circles larger than some threshold size 

        if (rule1 and rule2):
            calculated_property = some_function

            if condition_3:
                calculated_some_other_property = some_other_function

                if condition_4:
                    some_quantity = something
                    enclosing_circles[id] = float('{:.4f}'.format(log10(mass)))
                    some_parameter[id] = float('{:.3e}'.format(some_quantity))


    # choose all sub-circles' IDs enclosing the special pixel
    enclosing_circles_list = list(enclosing_circles.keys())
    some_parameter_list = list(some_parameter.keys())
    sub_circle_catalog += [(enclosing_circles[i], 1) for i in enclosing_circles_list]
    some_parameter_catalog += [(enclosing_circles[i], some_parameter[j]) for i, j in zip(enclosing_circles_list, some_parameter_list)]

# add up all special grids in each sub-circle when looping over all grids
for key, value in sub_circle_catalog:
    totals[key] = totals.get(key, 0) + value
totals_dict = collections.OrderedDict(sorted(totals.items()))
totals_list = list(totals.items())


with open(some_file_path, "a") as some_file:
    print('{}'.format(totals_list), file=some_file)
    some_file.close()
.
.
.
Run Code Online (Sandbox Code Playgroud)

gil*_*lch 5

第二个规则下的rule1和rule2花费的时间最长.

内联rule1rule2.and如果它知道第一部分是假的,则不会评估第二部分.也尝试交换它们,看看是否更好.

根据计算这些规则的详细信息,您可以找到其他快捷方式.


总是寻找瓶颈来找到瓶颈.您可以浪费大量时间来优化其他无用的部分.

可能的捷径; 不要浪费时间计算你不需要的东西.

通过内联循环避免嵌套循环中的函数调用.CPython中的呼叫有点慢.

展开内部循环以减少循环开销.

尽可能计算循环外的东西,而不是每次循环重做它.


考虑使用Nutika,Cython或PyPy编译整个事物.(或者只是Cython或Numba的慢速部分.)

考虑在Julia中重写这个部分,这可以更快,更容易地从Python调用.最好提取并调用整个内部循环,而不仅仅是它的主体,以避免每个循环的调用开销.

考虑尽可能使用numpy进行矢量化计算,即使它只是循环的一部分.Numpy的内部循环比Python快得多.这可能会占用更多内存.如果你可以使numpy矢量化工作,你可以使用CuPy(使用GPU或可以处理更大数据集的Dask)获得更大的加速.