Возвращать ответ в виде файла Excel, написанного с использованием многопроцессорной обработки, BytesIO, xlsxwriter - PullRequest
0 голосов
/ 16 января 2020

У меня есть следующая list схема:

multiple_years_data = [
    {
        'dates': ... (list of dates for one year),
        'values': ... (list of values for one year),
        'buffer': output
    },
    {
        'dates': ... (list of dates for another year),
        'values': ... (list of values for another year),
        'buffer': output
    },
    ... (and so on)
]

Все данные сверху я хочу вставить их в файл Excel с двумя столбцами (date, value) и для каждого dict из списка я хочу создать новое рабочее пространство.

Например, если бы в списке было 5 диктов, у меня было бы 5 рабочих пространств с данными, зависящими от диктата.

Имея столько данных, выполнение всего процесса вставки synchronously занимает некоторое время, поэтому я подумал о реализации multiprocessing, чтобы можно было добавить некоторую вычислительную мощность от других ядер. Теперь, если бы у меня были данные за 5 лет, я бы создал 5 процессов. С самого начала я попробовал это только в одном процессе и в один голос, и если это сработает, я добавлю больше процессов.

Кстати, я должен упомянуть, что я использую Django framework.

Итак, это самые важные части моего кода:

def add_one_year_to_excel(data):
    workbook = xlsxwriter.Workbook(data['output'])
    worksheet = data['buffer'].add_worksheet('first_worksheet')

    # insert those 2 lists of data(`dates`, `values`) in two columns
    worksheet.write_column(1, 0, data['dates'])
    worksheet.write_column(1, 1, data['values'])

    return workbook


output = BytesIO()
workbook = xlsxwriter.Workbook(output)

pool = Pool(1)
result = pool.apply(add_one_year_to_excel, multiple_years_data)
pool.close()

# this line makes so that i can automatically download the result file if i access the assigned url
response = HttpResponse(result.read(),
                                content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
response['Content-Disposition'] = f'attachment; filename=example.xlsx'
response['Access-Control-Expose-Headers'] = 'Content-Disposition'

return response

Я знаю, что некоторые части написаны немного плохо, но я попытался создать очень простую схему моего кода, чтобы вы могли понять мои проблема. Теперь проблема в том, что, как только результат из функции add_one_year_to_excel(data) возвращается, он получает проблемы c:

MaybeEncodingError at /api/v1/forecasted_profile_excel/
Error sending result: '<xlsxwriter.workbook.Workbook object at 0x7f5874306dc0>'. Reason: 'PicklingError("Can't pickle <class 'xlsxwriter.worksheet.Number'>: attribute lookup Number on xlsxwriter.worksheet failed")'

В конце я понял, что только BytesIO () может быть засечен, и если я добавлю лист, объект больше не может быть замаринован. Итак, вся проблема заключается в травлении, возврате и обмене данными между несколькими процессами. Я боролся с этой проблемой в течение 3 дней. Посмотрел на inte rnet, и все же я не могу сделать эту работу.

Итак, я спрашиваю вас, можете ли вы помочь мне решить эту проблему? Может быть, лучший способ сделать это, но тот же результат? Я немного новичок в этой области, поэтому, возможно, мой код написан не очень хорошо.

Заранее спасибо.

...