首页 > 解决方案 > Python/Django 循环优化

问题描述

我目前在 Django 网站上工作,并且在某个时候需要为模型数据中的图形生成数据集。在过去的几天里,我一直在尝试优化代码以生成该数据,但是对于一个数据集来说它仍然相对较慢,当网站启动时它肯定会变得更大。

我正在使用的模型如下所示:

class Prices(models.Model):
name = models.CharField(max_length=200, blank=False)
website = models.CharField(max_length=200, blank=False, choices=WEBSITES)
date= models.DateField('date', default=date.today(), blank=False, null=False)
price = models.IntegerField(default=0, blank=False, null=False)

class Meta:
    indexes = [
        models.Index(fields=['website']),
        models.Index(fields=['date'])
    ]

它在不同的网站上存储不同项目(由名称定义)的价格。对于模型的图形表示,我需要两个数组,一个包含所有日期作为 y 轴,一个包含该日期的项目价格(可能不可用,并非每个项目都有每天的日期条目在每个网站上)。所有这些都适用于每个网站。

我生成该数据的代码如下所示:

    for website in websites:
    iterator = Prices.objects.filter(website=website).iterator()
    data = []
    entry = next(iterator)
    for date in labels:
        if entry is not None and date == entry.date:
            data.append(entry.price* 0.01)
            entry = next(iterator, None)
        else:
            data.append(None)
     ... do stuff with data (not relevant for performance)

我遍历每个网站并从我的模型中检索所有价格数据。然后我遍历所有日期(在数组标签中),查看该日期条目是否可用,如果是,则将其添加到数组中,否则没有。有没有人有关于如何优化内部 for 循环的提示或想法,因为这就是我 90% 的性能问题的原因。

标签: pythondjangoperformancefor-loopoptimization

解决方案


这可能没有你想要的那么有效,但你可以试试这个。如果这仍然不能满足您的要求,那么我能想到的就是异步执行此操作。

iterator = Prices.objects.filter(website=website)

from collections import defaultdict
result = reduce(lambda acc, prices: acc[prices.date].append((prices.price * 0.01, prices.website)) or acc, filter(lambda x: x.date in labels, iterator), defaultdict(list))

异步执行此操作的一种方法是使用concurrent.futures 模块

ThreadPoolExecutor(max_workers = 10)(您可以像这样指定最大工人数)。

此外,如果您想要多个Processes而不是Threads。您可以简单地将ThreadPoolExecutor替换为ProcessPoolExecutor

result = defaultdict(list)
def reducer_function(price):
    if price.date in labels:
        result[price.date].append((prices.price * 0.01, prices.website))

with concurrent.futures.ThreadPoolExecutor() as executor:
    executor.map(reducer_function, iterator)

推荐阅读