В приложении django я пытаюсь проанализировать набор запросов, представляющий отдельные значения временных рядов x из n датчиков, в кортежи (t, x1, x2 ... x n ), а затем в объект json в формате, указанном здесь Google-диаграммами: https://developers.google.com/chart/interactive/docs/gallery/linechart
Нет значения используются в качестве заполнителей, если для заданной отметки времени от конкретного датчика не было зарегистрировано никакого значения
Время загрузки страницы является значительным для QuerySet с ~ 6500 строками (~ 3 секунды, запускается локально)
Это значительно дольше на сервере
http://54.162.202.222/pulogger/simpleview/?device=test
Профилирование указывает, что 99,9% времени тратится на _winapi.WaitForSingleObject (что я не могу интерпретировать), а ручное профилирование с таймером указывает, что виновником на стороне сервера является цикл while, который выполняет итерацию по QuerySet и группам значения в кортежи (строка 23 в моем примере кода)
Результаты выглядят следующим образом:
базовое получение (заняло 5 мс)
запрашиваемые данные (заняло 0 мс)
разделить данные по датчику (заняло 981 мс)
подготовленные метки / типы столбцов (заняло 0 мс)
подготовлено JSON (заняло 27 мс)
созданный контекст (заняло 0 мс)
Для полноты, функция синхронизации выглядит следующим образом:
def print_elapsed_time(ref_datetime, description):
print('{} (took {}ms)'.format(description, floor((datetime.now()-ref_datetime).microseconds/1000)))
return datetime.now()
Код, выполняющий обработку и генерирующий представление, выглядит следующим образом:
def simpleview(request):
time_marker = datetime.now()
device_name = request.GET['device']
device = Datalogger.objects.get(device_name=device_name)
sensors = Sensor.objects.filter(datalogger=device).order_by('pk')
sensor_count = len(sensors) # should be no worse than count() since already-evaluated and cached. todo: confirm
#assign each sensor an index for the tuples (zero is used for time/x-axis)
sensor_indices = {}
for idx, sensor in enumerate(sensors, start=1):
sensor_indices.update({sensor.sensor_name:idx})
time_marker = print_elapsed_time(time_marker, 'basic gets')
# process data into timestamp-grouped tuples accessible by sensor-index ([0] is timestamp)
raw_data = SensorDatum.objects.filter(sensor__datalogger__device_name=device_name).order_by('timestamp', 'sensor')
data = []
data_idx = 0
time_marker = print_elapsed_time(time_marker, 'queried data')
while data_idx < len(raw_data):
row_list = [raw_data[data_idx].timestamp]
row_list.extend([None]*sensor_count)
row_idx = 1
while data_idx < len(raw_data) and raw_data[data_idx].timestamp == row_list[0]:
row_idx = sensor_indices.get(raw_data[data_idx].sensor.sensor_name)
row_list[row_idx] = raw_data[data_idx].value
data_idx += 1
data.append(tuple(row_list))
time_marker = print_elapsed_time(time_marker, 'split data by sensor')
column_labels = ['Time']
column_types = ["datetime"]
for sensor in sensors:
column_labels.append(sensor.sensor_name)
column_types.append("number")
time_marker = print_elapsed_time(time_marker, 'prepared column labels/types')
gchart_json = prepare_data_for_gchart(column_labels, column_types, data)
time_marker = print_elapsed_time(time_marker, 'prepared json')
context = {
'device': device_name,
'sensor_count': sensor_count,
'sensor_indices': sensor_indices,
'gchart_json': gchart_json,
}
time_marker = print_elapsed_time(time_marker, 'created context')
return render(request, 'pulogger/simpleTimeSeriesView.html', context)
Я новичок в python, поэтому я ожидаю, что у меня плохой выбор операции / коллекции, которую я где-то использовал. Если я не слепой, он должен работать в O (n).
Очевидно, что это не вся проблема, поскольку она учитывает только часть кажущегося времени загрузки, но я думаю, что это хорошее место для начала.