Câu hỏi Bảng tính :: ParseExcel :: Luồng mất trình phân tích cú pháp của nó


Tôi có một bảng tính Excel 18M để phân tích và Spreadsheet::ParseExcel đã tiêu tốn rất nhiều bộ nhớ mà tôi phải chuyển sang Bảng tính :: ParseExcel :: Luồng. Nó hoạt động tốt trên máy ảo của tôi, nó hoạt động tốt trên máy chủ dàn dựng của chúng tôi, nhưng trên máy chủ sản xuất của chúng tôi (được cấu hình theo cùng một cách), tôi nhận được lỗi này:

Can't call method "transfer" on an undefined value at \
lib/Spreadsheet/ParseExcel/Stream/XLS.pm line 31.

Điều đó xuất phát từ đoạn mã sau:

my ($wb, $idx, $row, $col, $cell);
my $tmp = my $handler = sub {
  ($wb, $idx, $row, $col, $cell) = @_;
  $parser->transfer($main);  XXX here's where we die
};

my $tmp_p = $parser = Coro::State->new(sub {
  $xls->Parse($file);
  # Flag the generator that we're done
  undef $xls;
  # If we don't transfer back when done parsing,
  # it's an implicit program exit (oops!)
  $parser->transfer($main)
});
weaken($parser);

Các weaken trông có vẻ nghi ngờ, vì vậy tôi đã cố gắng không làm suy yếu trừ khi số tiền lớn hơn 1, nhưng vấn đề tương tự cũng xảy ra. Tôi đã thiết kế mã để có được một stacktrace và nhận được điều này:

parser is undefined at lib/Spreadsheet/ParseExcel/Stream/XLS.pm line 29.

Spreadsheet::ParseExcel::Stream::XLS::__ANON__                   \
  ('Spreadsheet::ParseExcel::Workbook=HASH(0x6cd4a08)', 0, 2, 1, \
  'Spreadsheet::ParseExcel::Cell=HASH(0x1387ce78)') called at    \
  /usr/share/perl5/Spreadsheet/ParseExcel.pm line 2152
Spreadsheet::ParseExcel::_NewCell(                               \ 
  'Spreadsheet::ParseExcel::Workbook=HASH(0x6cd4a08)', 2, 1,     \
  'Kind', 'PackedIdx', 'Val', 'Dean', 'FormatNo', 25, ...)       \
   called at /usr/share/perl5/Spreadsheet/ParseExcel.pm line 896
Spreadsheet::ParseExcel::_subLabelSST(                           \
  'Spreadsheet::ParseExcel::Workbook=HASH(0x6cd4a08)', 253, 10,  \
  '\x{2}\x{0}\x{1}\x{0}\x{19}\x{0}2\x{0}\x{0}\x{0}')             \
   called at /usr/share/perl5/Spreadsheet/ParseExcel.pm line 292
Spreadsheet::ParseExcel::parse(                                  \
  'Spreadsheet::ParseExcel=HASH(0x6cd1810)', '2013-09-13.xls')   \
   called at lib/Spreadsheet/ParseExcel/Stream/XLS.pm line 35
Spreadsheet::ParseExcel::Stream::XLS::__ANON__                   \
   called at new_importer.pl line 0

Điều đó nói với tôi rằng trình phân tích cú pháp đọc các hàng đầu tiên và thứ hai, nhưng nó chết trên hàng thứ ba vì một lý do nào đó.

Tôi đã cố gắng xây dựng lại Spreadsheet::ParseExcel::Stream và nó dường như không có bất kỳ lỗi nào (tất cả các bài kiểm tra đều vượt qua). Tôi cũng đã biên dịch lại Coro (cùng một kết quả).

Tôi bị hoang mang. Ai có ý tưởng gì không?


22
2017-10-01 17:19


gốc


bạn đã cố gắng để làm cho $ parser hiển thị một msg khi nó đi ra khỏi phạm vi? ví dụ: $ parser -> {__ debug_destroy} = DestroyNote-> new (). - Shmuel Fomberg
bạn có thể giảm nó thành một ví dụ chạy được không? - ysth
Sự suy yếu là cần thiết vì các tham chiếu vòng tròn trong các subon subson và các biến. Bạn có thể thấy rò rỉ bộ nhớ nếu bạn nhận xét ra làm suy yếu và sau đó tạo S :: PE :: S đối tượng trong một vòng lặp. Gán cho $ tmp_p đảm bảo trình phân tích cú pháp không biến mất cho đến khi nó được yêu cầu. - runrig


Các câu trả lời:


Vấn đề hóa ra khá kỳ lạ và trông giống như mã psuedo này:

stream1 = open first excel stream
sheet1  = stream1.sheet // get spreadsheet ready for reading

if in verbose mode:
    stream2 = open second excel stream
    sheet2  = stream2.sheet
    count++ while sheet2.get_row
    say "We have $count records"

Chúng tôi phát hiện ra rằng nếu và chỉ khi chúng tôi đang ở trong chế độ tiết thì vấn đề này có thể biểu hiện hay không. Bởi có hai luồng trỏ đến cùng một tài liệu, mã sản xuất của chúng tôi sẽ thất bại, mặc dù điều này làm việc tốt trên các hộp khác. Bằng cách đếm số hàng và đóng luồng đó trước mở luồng thông thường để đọc tài liệu, chúng tôi đã giải quyết được vấn đề.


15
2017-10-07 13:58



rt43250 không giải quyết được vấn đề tôi đang nghĩ đến. S :: PE vẫn không thể phân tích đồng thời hai hoặc nhiều bảng tính khi một hoặc nhiều trong số chúng sử dụng tùy chọn CellHandler (trong đó S :: PE :: S sử dụng). - runrig
Đã thêm một bản vá vào rt43250 để khắc phục vấn đề này. - runrig
Một bản vá w / kiểm tra là trên github. - runrig
Được cố định theo câu 0,60. Bây giờ tôi là người duy trì, mặc dù gần đây không tích cực lắm. - runrig
Và chỉ cần đề cập đến ... thông thường đây sẽ không phải là lỗi khi chỉ sử dụng S :: PE vì bảng tính được phân tích cú pháp đầy đủ trước khi phân tích cú pháp bất kỳ bảng tính nào khác. Điều này chỉ biểu hiện khi sử dụng S :: PE :: S vì nó biến đổi một cách kỳ diệu trình xử lý gọi lại từ bên trong ra thành một trình lặp. - runrig