Я хочу измерить время, необходимое GoLang для анализа XML-файла.Итак, я решил написать тест.
У меня есть функция, которая генерирует io.Reader
, который содержит XML-документ.
// PRIVATE: createSampleXMLReader creates an io.Reader instance that contains 10.000 '<Node />' elements which are
// suitable for running a benchmark test.
func createSampleXMLReader(
nodeElementCount int) io.Reader {
xmlContents := new(strings.Builder)
xmlContents.WriteString("<ROOT>\n")
for i := 0; i < nodeElementCount; i++ {
appendNodeXMLElement(xmlContents)
}
xmlContents.WriteString("</ROOT>")
return strings.NewReader(xmlContents.String())
}
// PRIVATE: appendNodeXMLElement appends a '<Node />' elements to an existing io.Reader instance.
func appendNodeXMLElement(
xmlDocument *strings.Builder) {
xmlDocument.WriteString("<Node id=\"0\" position=\"0\" depth=\"0\" parent=\"0\">\n")
xmlDocument.WriteString(" <Name>Name</Name>\n")
xmlDocument.WriteString(" <Description>Description</Description>\n")
xmlDocument.WriteString(" <OwnInformation>\n")
xmlDocument.WriteString(" <Title>Title</Title>\n")
xmlDocument.WriteString(" <Description>Description</Description>\n")
xmlDocument.WriteString(" </OwnInformation>\n")
xmlDocument.WriteString(" <Assets>\n")
xmlDocument.WriteString(" <Asset id=\"0\" position=\"0\" type=\"0\" category=\"0\">\n")
xmlDocument.WriteString(" <OriginalFile>OriginalFile</OriginalFile>\n")
xmlDocument.WriteString(" <Description>Description</Description>\n")
xmlDocument.WriteString(" <Uri>Uri</Uri>\n")
xmlDocument.WriteString(" </Asset>\n")
xmlDocument.WriteString(" <Asset id=\"1\" position=\"1\" type=\"1\" category=\"1\">\n")
xmlDocument.WriteString(" <OriginalFile>OriginalFile</OriginalFile>\n")
xmlDocument.WriteString(" <Description>Description</Description>\n")
xmlDocument.WriteString(" <Uri>Uri</Uri>\n")
xmlDocument.WriteString(" </Asset>\n")
xmlDocument.WriteString(" <Asset id=\"2\" position=\"2\" type=\"2\" category=\"2\">\n")
xmlDocument.WriteString(" <OriginalFile>OriginalFile</OriginalFile>\n")
xmlDocument.WriteString(" <Description>Description</Description>\n")
xmlDocument.WriteString(" <Uri>Uri</Uri>\n")
xmlDocument.WriteString(" </Asset>\n")
xmlDocument.WriteString(" <Asset id=\"3\" position=\"3\" type=\"3\" category=\"3\">\n")
xmlDocument.WriteString(" <OriginalFile>OriginalFile</OriginalFile>\n")
xmlDocument.WriteString(" <Description>Description</Description>\n")
xmlDocument.WriteString(" <Uri>Uri</Uri>\n")
xmlDocument.WriteString(" </Asset>\n")
xmlDocument.WriteString(" <Asset id=\"4\" position=\"4\" type=\"4\" category=\"4\">\n")
xmlDocument.WriteString(" <OriginalFile>OriginalFile</OriginalFile>\n")
xmlDocument.WriteString(" <Description>Description</Description>\n")
xmlDocument.WriteString(" <Uri>Uri</Uri>\n")
xmlDocument.WriteString(" </Asset>\n")
xmlDocument.WriteString(" </Assets>\n")
xmlDocument.WriteString(" <Synonyms>\n")
xmlDocument.WriteString(" <Synonym>Synonym 0</Synonym>\n")
xmlDocument.WriteString(" <Synonym>Synonym 1</Synonym>\n")
xmlDocument.WriteString(" <Synonym>Synonym 2</Synonym>\n")
xmlDocument.WriteString(" <Synonym>Synonym 3</Synonym>\n")
xmlDocument.WriteString(" <Synonym>Synonym 4</Synonym>\n")
xmlDocument.WriteString(" </Synonyms>\n")
xmlDocument.WriteString("</Node>\n")
}
Затем у меня есть функция, котораяфактически анализирует этот XML-документ.
// PRIVATE: parseXML parses an io.Reader instance into a 'Node' struct.
func parseXML(
xmlReader io.Reader) {
xmlDecoder := xml.NewDecoder(xmlReader)
for {
token, _ := xmlDecoder.Token()
if token == nil {
break
}
switch element := token.(type) {
case xml.StartElement:
if element.Name.Local == "Node" {
decodeNodeElement(xmlDecoder, &element)
}
}
}
}
// PRIVATE: decodeNodeElement decodes a '<Node />' element into a 'Node' struct.
func decodeNodeElement(
xmlDecoder *xml.Decoder,
element *xml.StartElement) {
node := new(model.Node)
xmlDecoder.DecodeElement(node, element)
}
Затем у меня есть функция, которая выполняет тест:
// PRIVATE: runBenchmarkParseXML performs a benchmark that parses an XML document that contains the given number of
// '<Node />' element.
func runBenchmarkParseXML(
nodeCount int,
benchmark *testing.B) {
// Arrange.
xmlReader := createSampleXMLReader(nodeCount)
// Act.
for i := 0; i < benchmark.N; i++ {
parseXML(xmlReader)
}
}
И затем у меня есть 5 функций, которые выполняют тест.Они предназначены для элементов 1, 10, 100, 1000 и 10000 в документе XML.
func BenchmarkParseXML1(benchmark *testing.B) { runBenchmarkParseXML(1, benchmark) }
func BenchmarkParseXML10(benchmark *testing.B) { runBenchmarkParseXML(10, benchmark) }
func BenchmarkParseXML100(benchmark *testing.B) { runBenchmarkParseXML(100, benchmark) }
func BenchmarkParseXML1000(benchmark *testing.B) { runBenchmarkParseXML(1000, benchmark) }
func BenchmarkParseXML10000(benchmark *testing.B) { runBenchmarkParseXML(10000, benchmark) }
Когда я запускаю этот тест, я вижу следующий вывод:
BenchmarkParseXML1-4 5000000 226 ns/op
BenchmarkParseXML10-4 10000000 230 ns/op
BenchmarkParseXML100-4 5000000 226 ns/op
BenchmarkParseXML1000-4 5000000 254 ns/op
BenchmarkParseXML10000-4 1 1690998100 ns/op
Как это возможно, что есть такая разница в тесте, который анализирует XML-файл, который содержит 10.000 элементов, а остальные значения времени теста стабильны?
Является ли мой тест новым или реализация метода ParseXMLНеправильно.
Редактировать: Структура узла
// Node represents a '<Node />' element in the XML document.
type Node struct {
ID int `xml:"id,attr"`
Position int `xml:"position,attr"`
Depth int `xml:"depth,attr"`
Parent string `xml:"parent,attr"`
Name string `xml:"Name"`
Description string `xml:"Description"`
OwnInformation struct {
Title string `xml:"Title"`
Description string `xml:"Description"`
} `xml:"OwnInformation"`
Assets []struct {
ID string `xml:"id,attr"`
Position int `xml:"position,attr"`
Type string `xml:"type,attr"`
Category int `xml:"category,attr"`
OriginalFile string `xml:"OriginalFile"`
Description string `xml:"Description"`
URI string `xml:"Uri"`
} `xml:"Assets>Asset"`
Synonyms []string `xml:"Synonyms>Synonym"`
}
Заранее благодарен за любые указания.