-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Add calculation cache to improve CalcCellValue performance #2144
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #2144 +/- ##
=======================================
Coverage 99.47% 99.47%
=======================================
Files 32 32
Lines 25704 25740 +36
=======================================
+ Hits 25569 25605 +36
Misses 72 72
Partials 63 63
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
xuri
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your PR. We need add any cache cautiously, after these changes we also need remove cache in following scenario:
- RemoveCol
- RemoveRow
- DuplicateRow
- DuplicateRowTo
- SetSheetCol
And update or delete cache when:
- SetSheetName
- DeleteSheet
Consider if other scenario needed.
Thanks for your quick respond! New additions in this commit: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code conflicts need resolve.
so sorry, the conflict was caused by my local auto-formatting. I've resolved it by keeping the original content from master |
|
This is really exciting! I have some very large workbooks this should help out on a ton. |
|
Ping @xuri |
|
Will take review for this. |
xuri
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for late reply, I've left some comments.
| // err := f.MoveSheet("Sheet2", "Sheet1") | ||
| func (f *File) MoveSheet(source, target string) error { | ||
| f.clearCalcCache() | ||
| if strings.EqualFold(source, target) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does clear calc cache on move sheet order is required?
sheet.go
Outdated
| // sheet name in the formula or reference associated with the cell. So there | ||
| // may be problem formula error or reference missing. | ||
| func (f *File) SetSheetName(source, target string) error { | ||
| f.clearCalcCache() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clear calc cache after sheet name checking.
| // as formulas, charts, and so on. If there is any referenced value of the | ||
| // worksheet, it will cause a file error when you open it. The excelize only | ||
| // partially updates these references currently. | ||
| func (f *File) DuplicateRow(sheet string, row int) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the DuplicateRow, DuplicateRowTo, InsertCol and InsertRow functions, we can clear calc cache in f.adjustHelper function instead of call f.clearCalcCache on each functions.
xuri
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Due to formula function may reference defined name or table name, so we need also clear calc cache in SetDefinedName, DeleteDefinedName, AddPivotTable, DeletePivotTable, AddTable and DeleteTable functions.
cell.go
Outdated
| // | ||
| // err := f.SetCellHyperLink("Sheet1", "A3", "Sheet1!A40", "Location") | ||
| func (f *File) SetCellHyperLink(sheet, cell, link, linkType string, opts ...HyperlinkOpts) error { | ||
| f.clearCalcCache() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to clear calc cache on set cell hyperlink.
cell.go
Outdated
| // | ||
| // err := f.SetSheetRow("Sheet1", "B6", &[]interface{}{"1", nil, 2}) | ||
| func (f *File) SetSheetRow(sheet, cell string, slice interface{}) error { | ||
| f.clearCalcCache() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The SetSheetCol and SetSheetRow will call SetCellValue, so we needn't clear calc cache at here.
col.go
Outdated
| // worksheet, it will cause a file error when you open it. The excelize only | ||
| // partially updates these references currently. | ||
| func (f *File) InsertCols(sheet, col string, n int) error { | ||
| f.clearCalcCache() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clear calc cache in f.adjustHelper function would be better approach.
col.go
Outdated
| // worksheet, it will cause a file error when you open it. The excelize only | ||
| // partially updates these references currently. | ||
| func (f *File) RemoveCol(sheet, col string) error { | ||
| f.clearCalcCache() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above, clear calc cache in f.adjustHelper function.
rows.go
Outdated
| // worksheet, it will cause a file error when you open it. The excelize only | ||
| // partially updates these references currently. | ||
| func (f *File) InsertRows(sheet string, row, n int) error { | ||
| f.clearCalcCache() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clear calc cache in f.adjustHelper.
sheet.go
Outdated
| // } | ||
| // err = f.CopySheet(0, index) | ||
| func (f *File) CopySheet(from, to int) error { | ||
| f.clearCalcCache() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clear calc in the f.copySheet function.
calc.go
Outdated
| func (f *File) clearCalcCache() { | ||
| f.calcCacheMu.Lock() | ||
| defer f.calcCacheMu.Unlock() | ||
| f.calcCache.Range(func(key, value interface{}) bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we using f.calcCache.Clear() instead of range each key?
PR Details
Add calculation cache to improve CalcCellValue performance
Description
Implements a calculation cache mechanism for
CalcCellValueto significantly improve performance when calculating formulas repeatedly. The cache stores calculated results and automatically invalidates when cells are modified.Related Issue
Fixes #2057 - Performance enhancement - cache calculated values
Motivation and Context
As described in #2057, Excelize doesn't cache calculated values from
CalcCellValue, causing expensive formulas to be recalculated every time they are referenced by other cells. This leads to poor performance when dealing with complex formula dependencies.Example scenario:
Solution implemented:
sync.MapSetCellX()function is called"sheet!cell"Performance improvement:
How Has This Been Tested
Test coverage includes:
Types of changes
☑️ New feature (non-breaking change which adds functionality)
☐ Docs change / refactoring / dependency upgrade
☐ Bug fix (non-breaking change which fixes an issue)
☐ Breaking change (fix or feature that would cause existing functionality to change)
Checklist
☑️ My code follows the code style of this project.
☐ My change requires a change to the documentation.
☐ I have updated the documentation accordingly.
☑️ I have read the CONTRIBUTING document.
☑️ I have added tests to cover my changes.
☑️ All new and existing tests passed.
Implementation Details
Modified Files:
excelize.go: Added cache fields (calcCache sync.Map,calcCacheMu sync.RWMutex) to File structcalc.go: Implemented caching logic inCalcCellValue()+ addedclearCalcCache()helpercell.go: Added cache clearing to all 12 Set functionscalc_test.go: Added 3 comprehensive cache test functions