【Django-功能优化】存储、循环、操作选择对代码性能的影响

功能开发背景

港口货轮需要进行集装箱的装卸任务:

【Django-功能优化】存储、循环、操作选择对代码性能的影响_第1张图片

船上的每一个集装箱,可以用三个维度的坐标来唯一定位:(bay, column, layer),这三个维度结合其他一些固有信息,构成了一个箱子的字段属性,存储在箱子数据表中。

【Django-功能优化】存储、循环、操作选择对代码性能的影响_第2张图片

现在需要以bay为单位,对bay内所有column、layer下的箱子,按照特有作业优先级进行作业顺序的编号(优先级从高到低:40尺-单钩箱子>20尺-双钩箱子>20尺-单钩箱子)。

即某个bay下,所有column最上层的箱子,统计他们的优先级,取其优先级最高的特定优先级进行作业,等到所有column最高层的箱子没有该优先级的箱子,按照低一级的优先级进行作业。如此循环往复三个优先级,直到所有的箱子都被编上作业顺序。

实现思路

大意如此,细节上的约束限制条件,不展开描述

  1. 获取船舶所有的bay信息
  2. 针对每一个bay信息,通过Django ORM查询数据库并返回满足条件的箱子集合
  3. 获取这些箱子集合包含的column、layer,并存储在列表中
  4. 两层循环遍历每一个箱子(按照层数和列数:从上到下(层),从左到右(列)遍历):

不用双层遍历的算法难度太大,构思不出来

for lay in layers:
    for col in columns:
        pass
  1. 在 优先级i 遍历的过程中,如果某列的箱子优先级不是i,则标记该列,在i优先级的后续遍历过程中不再考虑该列的箱子。

代码实现细节带来的速度差异

箱子数量计数

# 老版
for lay in layers:
    for col in lay_columns[lay]:
        boxes_selected = temp_queryset.filter(box_column=col, box_layer=lay)
        # ========================================
        len_boxes_selected = boxes_selected.count()
		# ========================================
        
        if len_boxes_selected == 2:
            if boxes_selected[0].is_work_together == 1:
                self.boxes_number_1(boxes_selected)
            else:
                self.boxes_number_2(boxes_selected)

        elif len_boxes_selected == 1:
            self.boxes_number_1(boxes_selected)

        else:
            pass

# 新版
for lay in layers:
    for col in lay_columns[lay]:
        boxes_selected = temp_queryset.filter(box_column=col, box_layer=lay)
        # ========================================
        len_boxes_selected = len(boxes_selected)
		# ========================================
        
        if len_boxes_selected == 2:
            if boxes_selected[0].is_work_together == 1:
                self.boxes_number_1(boxes_selected)
            else:
                self.boxes_number_2(boxes_selected)

        elif len_boxes_selected == 1:
            self.boxes_number_1(boxes_selected)

        else:
            pass

对计数后的查询集进行修改操作,用len()函数要比count()函数,效率高一点

参考文章:https://blog.csdn.net/qq_39187019/article/details/108170726

箱子列和层数的获取方式

# 老版
layer = [86, 84, 82, 80, 78, 76]
column = [16, 14, 12, 10, 8, 6, 4, 2, 0, 1, 3, 5, 7, 9, 11, 13, 15]


# 新版
layer = [86, 84, 82, 80, 78, 76]
column = {
    86:[16, 14, 12, 10, 8, 6, 4, 2, 0, 1, 3, 5, 7, 9, 11, 13, 15],
    84:[14, 12, 10, 8, 6, 4, 2, 0, 1, 3, 5, 7, 9, 11],
    82:[16, 14, 12, 10, 8, 6, 4, 2, 0, 1, 3, 5, 7, 9, 11, 13, 15],
    80:[10, 8, 6, 4, 2, 0, 1, 3, 5, 7, 9, 11, 13, 15],
    78:[16, 14, 12, 10, 8, 6, 4, 2, 0, 1, 3, 5, 7, 9, 11, 13, 15],
    76:[16, 14, 12, 10, 8, 6, 4, 2, 0, 1, 3, 5, 7]
}

老版:获取这个bay下所有箱子里面,涉及到的列和层

  1. 该方法十分方便的获取列和层
  2. 但是存在冗余,特定列,特定层下是没有箱子的,比如:(84, 16)

新版:获取这个bay下所有箱子里面,涉及到的层,再获取特定层下面涉及到的列信息

  1. 该方法相较于老版,在获取列信息上会更加耗时
  2. 但是不存在冗余,只要是遍历到的层、列,就一定能保证有箱子

整体计算下来,新版更加节省时间

结果存储方式的不同

# 老版本
self.numbered_boxes |= changed_queryset

# 新版本
for box in changed_queryset:
	self.numbered_boxes.append(box)

老版:对已经编号的箱子集合进行并集操作

  1. 最终的存储结果:

新版:在对箱子编号的时候,对箱子进行append操作

  1. 最终的存储结果:[, , …]

运算结果对比

上述改动,都是逐一改变的,每次改变都会有时间上的节省。

下边仅展示最终结果

数据量:10307条数据

【Django-功能优化】存储、循环、操作选择对代码性能的影响_第3张图片

运算时间

版本 运算时长(s)
老版 316
新版 143

老版

【Django-功能优化】存储、循环、操作选择对代码性能的影响_第4张图片

新版

【Django-功能优化】存储、循环、操作选择对代码性能的影响_第5张图片

你可能感兴趣的:(#,Django,django,python,后端)