Inserting lots of rows gets disproportionately slower the more rows you insert.
worksheet.Rows(1).InsertRowsBelow(1000); - OK
worksheet.Rows(1).InsertRowsBelow(10000); - Slow
worksheet.Rows(1).InsertRowsBelow(100000); - I gave up waiting...
It looks like there is a hash collision with RangeShiftedRowsDelegate / RangeShiftedColumnsDelegate. One of these delegates is created for each row, but each delegate object returns the same value of .GetHashCode().
When XLRangeBase.Dispose() is called, it removes the delegates for the 10000 rows just created one by one. The MulticastDelegate therefore has to search through all items one-by-one (because they are all in the same hash bucket). As this is done row by row, the performance is proportional to the square of the number of rows (it has to search ( 10000 * 10000 / 2 ) items to do all the removals).
I'm working on a fix (involving changing from delegates to a HashSet of the objects involved) so a patch may be available later.
Comments: So i try to use threadpool to deal Dispose method,And i don't find any wrong with the threadpool XLRangeRows.cs Try: ThreadPool.QueueUserWorkItem(new WaitCallback((x) => { if (_ranges != null) _ranges.ForEach(r => r.Dispose()); }));
worksheet.Rows(1).InsertRowsBelow(1000); - OK
worksheet.Rows(1).InsertRowsBelow(10000); - Slow
worksheet.Rows(1).InsertRowsBelow(100000); - I gave up waiting...
It looks like there is a hash collision with RangeShiftedRowsDelegate / RangeShiftedColumnsDelegate. One of these delegates is created for each row, but each delegate object returns the same value of .GetHashCode().
When XLRangeBase.Dispose() is called, it removes the delegates for the 10000 rows just created one by one. The MulticastDelegate therefore has to search through all items one-by-one (because they are all in the same hash bucket). As this is done row by row, the performance is proportional to the square of the number of rows (it has to search ( 10000 * 10000 / 2 ) items to do all the removals).
I'm working on a fix (involving changing from delegates to a HashSet of the objects involved) so a patch may be available later.
Comments: So i try to use threadpool to deal Dispose method,And i don't find any wrong with the threadpool XLRangeRows.cs Try: ThreadPool.QueueUserWorkItem(new WaitCallback((x) => { if (_ranges != null) _ranges.ForEach(r => r.Dispose()); }));