OSError: [Errno 24] Слишком много открытых файлов при загрузке 9000+ файлов csv через админку Django
У меня возникли трудности с загрузкой файлов csv, содержащих данные для заполнения базы данных моего проекта Django. Я обслуживаю свой проект, используя Django 3.1 и Gunicorn, если это важно. Я обратился к нескольким постам на stack overflow по тому же вопросу, но ни один из них не решил эту проблему. Просто перечислим шаги, которые я предпринял для решения этой проблемы:
- Запустил
ulimit -n 50000в терминале, чтобы увеличить максимальное количество файлов, которые могут быть открыты, как было предложено в этом посте . - Использовал
ulimit -n, чтобы найти максимальное количество файлов, которые могут быть открыты и изменил конфигурацию этого предела в файлеlimits.conf, как было предложено в этом посте , чтобы изменить системные ограничения. Я подтвердил это изменение, запустивulimit -a.
- Я полагал, что это может быть проблема с памятью и что Linux ограничивает максимальный объем доступного пространства на куче, поэтому я изменил конфигурацию и для этого. К счастью, это не было проблемой памяти, так как использование оперативной памяти было чрезвычайно стабильным, согласно моей панели управления .
Вот код, связанный с моей проблемой:
admin.py
class CsvImportForm(forms.Form):
csv_upload = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
@admin.register(dummyClass)
class dummyClassAdmin(admin.ModelAdmin):
search_fields = search fields
list_display = stuff to display in a list
list_filter = thing that filters objects
prepopulated_fields = prepopulated field
@csrf_exempt
def get_urls(self):
urls = super().get_urls()
new_urls = [path('upload-csv/', self.upload_csv),]
return new_urls + urls
@csrf_exempt
def upload_epcsv(self, request):
if request.method == "POST":
csv_files = request.FILES.getlist('csv_upload')
errors = []
for csv_file in csv_files:
if not(csv_file.name.endswith('.csv') or csv_file.name.endswith('.xlsx')):
messages.warning(request, 'The wrong file type was uploaded')
return HttpResponseRedirect(request.path_info)
csv_data = None
if csv_file.name.endswith('.xlsx'):
csv_data = pd.read_excel(csv_file, sheet_name=0, engine='openpyxl')
else:
csv_data = pd.read_csv(csv_file)
csv_data.fillna("https://www.a.com", inplace=True)
*Insert code that parses through dataframe and populates fields in database with data
url = reverse('admin:index')
return HttpResponseRedirect(url)
form = CsvImportForm()
data = {"form": form}
return render(request, "admin/csv_upload.html", data)
Вот трассировка ошибки:
Изменили имена путей в целях конфиденциальности
Похоже, что проблема в том, что pd.read_csv(csv_file) не закрывается csv_file, тип которого UploadedFile.
Эти открытые файлы никогда не закрываются и в результате происходит утечка.
Вы можете попробовать войти в систему csv_data.closed и посмотреть, открыта ли она еще.
Решения:
- (Рекомендуем) Используйте временный_путь_файла при чтении, он закроет файл после чтения.
- Закройте его самостоятельно
csv_file.close()наконец.