optimize memory allocation (#722)

* optimize marshal

* optimize mem alloc

* add benchmark testing

* add NewSheetWithRowNum testing

* sync struct fields order

* add BenchmarkNewSheetWithStreamWriter

* delete NewSheetWithRowNum and benchmark test
formula
Ted 4 years ago committed by GitHub
parent 9d470bb38f
commit fcca8a3838
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -206,8 +206,9 @@ func CoordinatesToCellName(col, row int) (string, error) {
if col < 1 || row < 1 {
return "", fmt.Errorf("invalid cell coordinates [%d, %d]", col, row)
}
//Using itoa will save more memory
colname, err := ColumnNumberToName(col)
return fmt.Sprintf("%s%d", colname, row), err
return colname + strconv.Itoa(row), err
}
// boolPtr returns a pointer to a bool with the given value.

@ -120,18 +120,26 @@ func (f *File) workBookWriter() {
// workSheetWriter provides a function to save xl/worksheets/sheet%d.xml after
// serialize structure.
func (f *File) workSheetWriter() {
// optimize memory alloc
var arr []byte
buffer := bytes.NewBuffer(arr)
encoder := xml.NewEncoder(buffer)
for p, sheet := range f.Sheet {
if sheet != nil {
for k, v := range sheet.SheetData.Row {
f.Sheet[p].SheetData.Row[k].C = trimCell(v.C)
}
output, _ := xml.Marshal(sheet)
f.saveFileList(p, replaceRelationshipsBytes(f.replaceNameSpaceBytes(p, output)))
// reusing buffer
encoder.Encode(sheet)
f.saveFileList(p, replaceRelationshipsBytes(f.replaceNameSpaceBytes(p, buffer.Bytes())))
ok := f.checked[p]
if ok {
delete(f.Sheet, p)
f.checked[p] = false
}
buffer.Reset()
}
}
}

@ -3,6 +3,7 @@ package excelize
import (
"fmt"
"path/filepath"
"strconv"
"strings"
"testing"
@ -344,3 +345,36 @@ func TestSetSheetName(t *testing.T) {
f.SetSheetName("Sheet1", "Sheet1")
assert.Equal(t, "Sheet1", f.GetSheetName(0))
}
func BenchmarkNewSheet(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
newSheetWithSet()
}
})
}
func newSheetWithSet() {
file := NewFile()
file.NewSheet("sheet1")
for i := 0; i < 1000; i++ {
file.SetCellInt("sheet1", "A"+strconv.Itoa(i+1), i)
}
file = nil
}
func BenchmarkFile_SaveAs(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
newSheetWithSave()
}
})
}
func newSheetWithSave() {
file := NewFile()
file.NewSheet("sheet1")
for i := 0; i < 1000; i++ {
file.SetCellInt("sheet1", "A"+strconv.Itoa(i+1), i)
}
file.Save()
}

@ -313,20 +313,20 @@ type xlsxSheetData struct {
// xlsxRow directly maps the row element. The element expresses information
// about an entire row of a worksheet, and contains all cell definitions for a
// particular row in the worksheet.
type xlsxRow struct {
Collapsed bool `xml:"collapsed,attr,omitempty"`
type xlsxRow struct { // alignment word
C []xlsxC `xml:"c"`
R int `xml:"r,attr,omitempty"`
Spans string `xml:"spans,attr,omitempty"`
S int `xml:"s,attr,omitempty"`
CustomFormat bool `xml:"customFormat,attr,omitempty"`
CustomHeight bool `xml:"customHeight,attr,omitempty"`
Hidden bool `xml:"hidden,attr,omitempty"`
Ht float64 `xml:"ht,attr,omitempty"`
Hidden bool `xml:"hidden,attr,omitempty"`
CustomHeight bool `xml:"customHeight,attr,omitempty"`
OutlineLevel uint8 `xml:"outlineLevel,attr,omitempty"`
Ph bool `xml:"ph,attr,omitempty"`
R int `xml:"r,attr,omitempty"`
S int `xml:"s,attr,omitempty"`
Spans string `xml:"spans,attr,omitempty"`
ThickBot bool `xml:"thickBot,attr,omitempty"`
Collapsed bool `xml:"collapsed,attr,omitempty"`
ThickTop bool `xml:"thickTop,attr,omitempty"`
C []xlsxC `xml:"c"`
ThickBot bool `xml:"thickBot,attr,omitempty"`
Ph bool `xml:"ph,attr,omitempty"`
}
// xlsxSortState directly maps the sortState element. This collection
@ -456,6 +456,7 @@ type DataValidation struct {
// s (Shared String) | Cell containing a shared string.
// str (String) | Cell containing a formula string.
//
// fixme: how to make this structure smaller; cur size is 152 bytes. it's be too bigger.
type xlsxC struct {
XMLName xml.Name `xml:"c"`
XMLSpace xml.Attr `xml:"space,attr,omitempty"`

Loading…
Cancel
Save