Django:导致 InMemoryUploadedFile 过早关闭的线程?
Django: Thread causing InMemoryUploadedFile to prematurely close?
美好的一天,
我遇到一个问题,CSV 文件发送到视图,然后传递到新线程进行处理,有时会过早关闭,我无法弄清楚原因。这种行为是间歇性的,只有在我切换到使用新线程处理文件后才开始发生。
这是我处理文件的原始方式并且它有效,但对于大文件它会导致客户端出现超时问题:
class LoadCSVFile(APIView):
permission_class = (IsAuthenticated,)
parser_classes = [FormParser, MultiPartParser]
def post(self, request):
file = request.FILES['file']
data_set = file.read().decode('utf-8')
io_string = io.StringIO(data_set)
for row_data in csv.reader(io_string, delimiter=',', quotechar='"'):
print('row_data:', row_data)
return Response({ 'message': 'File received and is currently processing.', 'status_code': status.HTTP_200_OK }, status.HTTP_200_OK)
所以我现在在新线程中处理文件,如下所示:
class LoadCSVFile(APIView):
permission_class = (IsAuthenticated,)
parser_classes = [FormParser, MultiPartParser]
def post(self, request):
request_handler = RequestHandler(request)
csv_handler = CSVHandler(request.FILES['file'])
# Fire and forget the file processing.
t = threading.Thread(target=request_handler.resolve, kwargs={ 'csv_handler': csv_handler })
t.start()
return Response({ 'message': 'File received and is currently processing.', 'status_code': status.HTTP_200_OK }, status.HTTP_200_OK)
class RequestHandler(object):
def __init__(self, request : Request):
self.request = request
def resolve(self, **kwargs):
csv_handler = kwargs['csv_handler']
try:
print('Processing file...')
csv_handler.process_file()
except Exception as e:
print('process_file level error:', e)
class CSVHandler(object):
def __init__(self, file):
self.file = file
def get_reader(self):
# Error is raised at the following line: "I/O operation on closed file."
data_set = self.file.read().decode('utf-8')
io_string = io.StringIO(data_set)
return csv.reader(io_string, delimiter=',', quotechar='"')
def process_file(self, **kwargs):
for row_data in self.get_reader():
print('row_data:', row_data)
有一段时间很好,但后来我开始注意到偶尔 I/O 错误。
- 大文件(5000 行)和小文件(2 行)都会发生这种情况。
- 我可以上传 50 次而没有看到错误,然后它会连续发生 2 或 3 次。或者介于两者之间的任何地方。
- 在启动线程之前,请求保存在 RequestHandler 中,文件保存在 CSVHandler 中,我不知道如何让 InMemoryUploadedFile 保持活动状态,直到我需要它 (
csv_handler.get_reader()
)。
有什么建议吗?
感谢您的宝贵时间。
此问题是由主线程在 csv_handler.get_reader()
打开 CSV 文件之前从 POST 请求返回引起的。我仍然不确定 RequestHandler
和 CSVHandler
引用 request
和 file
对象时文件是如何丢失的。也许这是 Django 的事。
我通过将 reader 逻辑向上移动到 CSVHandler
构造函数并使用锁来防止竞争条件来修复它。
class CSVHandler(object):
def __init__(self, file):
self.lock = threading.Lock()
with self.lock:
self.file = file
data_set = self.file.read().decode('utf-8')
io_string = io.StringIO(data_set)
self.reader = csv.reader(io_string, delimiter=',', quotechar='"')
def process_file(self, **kwargs):
for row_data in self.reader:
print('row_data:', row_data)
美好的一天,
我遇到一个问题,CSV 文件发送到视图,然后传递到新线程进行处理,有时会过早关闭,我无法弄清楚原因。这种行为是间歇性的,只有在我切换到使用新线程处理文件后才开始发生。
这是我处理文件的原始方式并且它有效,但对于大文件它会导致客户端出现超时问题:
class LoadCSVFile(APIView):
permission_class = (IsAuthenticated,)
parser_classes = [FormParser, MultiPartParser]
def post(self, request):
file = request.FILES['file']
data_set = file.read().decode('utf-8')
io_string = io.StringIO(data_set)
for row_data in csv.reader(io_string, delimiter=',', quotechar='"'):
print('row_data:', row_data)
return Response({ 'message': 'File received and is currently processing.', 'status_code': status.HTTP_200_OK }, status.HTTP_200_OK)
所以我现在在新线程中处理文件,如下所示:
class LoadCSVFile(APIView):
permission_class = (IsAuthenticated,)
parser_classes = [FormParser, MultiPartParser]
def post(self, request):
request_handler = RequestHandler(request)
csv_handler = CSVHandler(request.FILES['file'])
# Fire and forget the file processing.
t = threading.Thread(target=request_handler.resolve, kwargs={ 'csv_handler': csv_handler })
t.start()
return Response({ 'message': 'File received and is currently processing.', 'status_code': status.HTTP_200_OK }, status.HTTP_200_OK)
class RequestHandler(object):
def __init__(self, request : Request):
self.request = request
def resolve(self, **kwargs):
csv_handler = kwargs['csv_handler']
try:
print('Processing file...')
csv_handler.process_file()
except Exception as e:
print('process_file level error:', e)
class CSVHandler(object):
def __init__(self, file):
self.file = file
def get_reader(self):
# Error is raised at the following line: "I/O operation on closed file."
data_set = self.file.read().decode('utf-8')
io_string = io.StringIO(data_set)
return csv.reader(io_string, delimiter=',', quotechar='"')
def process_file(self, **kwargs):
for row_data in self.get_reader():
print('row_data:', row_data)
有一段时间很好,但后来我开始注意到偶尔 I/O 错误。
- 大文件(5000 行)和小文件(2 行)都会发生这种情况。
- 我可以上传 50 次而没有看到错误,然后它会连续发生 2 或 3 次。或者介于两者之间的任何地方。
- 在启动线程之前,请求保存在 RequestHandler 中,文件保存在 CSVHandler 中,我不知道如何让 InMemoryUploadedFile 保持活动状态,直到我需要它 (
csv_handler.get_reader()
)。
有什么建议吗?
感谢您的宝贵时间。
此问题是由主线程在 csv_handler.get_reader()
打开 CSV 文件之前从 POST 请求返回引起的。我仍然不确定 RequestHandler
和 CSVHandler
引用 request
和 file
对象时文件是如何丢失的。也许这是 Django 的事。
我通过将 reader 逻辑向上移动到 CSVHandler
构造函数并使用锁来防止竞争条件来修复它。
class CSVHandler(object):
def __init__(self, file):
self.lock = threading.Lock()
with self.lock:
self.file = file
data_set = self.file.read().decode('utf-8')
io_string = io.StringIO(data_set)
self.reader = csv.reader(io_string, delimiter=',', quotechar='"')
def process_file(self, **kwargs):
for row_data in self.reader:
print('row_data:', row_data)