Ich analysiere jeden Tag XML unter http://manga-now.com, aber ich habe verglichen, wie es schneller wäre, wenn ich die Python-Implementierung in Go ändern würde. Da ich nur die Parsing-Geschwindigkeit vergleichen möchte, messe ich die Geschwindigkeit von dem Zustand, in dem XML in den Speicher eingelesen wird, bis die Erfassung jedes Elements abgeschlossen ist.
Verwenden Sie zunächst die Amazon Product Advertising API, um die XML-Datei der Buchinformationen zu löschen und in einer Datei zu speichern.
$ mkdir xmls
$ go run get_books_xml.go
Wenn Sie AccessKey, SecretKey und AssociateTag in die entsprechenden ändern und ausführen, werden 145 Dateien im xmls-Verzeichnis gespeichert. Eine Datei enthält Informationen für bis zu 10 Bücher, insgesamt 1442 Bücher.
parse_amazon_xml.py
# -*- coding:utf-8 -*-
import time
from lxml import objectify
class ImageInfo:
def __init__(self):
self.url = ''
self.width = ''
self.height = ''
class BookInfo:
def __init__(self):
self.asin = ''
self.title = ''
self.binding = ''
self.author = ''
self.publisher = ''
self.publicationDate = ''
self.images = {}
def getText(dom, tag):
return getattr(dom, tag).text if tag in dom else ''
def parseXmls(xmls):
bookInfos = []
for xml in xmls:
dom = objectify.fromstring(xml)
for item in dom.Items.Item:
bookInfo = BookInfo()
bookInfo.asin = item.ASIN.text
attr = item.ItemAttributes
bookInfo.title = getText(attr, 'Title')
bookInfo.binding = getText(attr, 'Binding')
bookInfo.author = getText(attr, 'Author')
bookInfo.publisher = getText(attr, 'Publisher')
bookInfo.publicationDate = getText(attr, 'PublicationDate')
imageLabels = ['SmallImage', 'MediumImage', 'LargeImage']
for imageLabel in imageLabels:
image = ImageInfo()
if imageLabel in item:
image.url = getattr(item, imageLabel).URL.text
image.width = int(getattr(item, imageLabel).Width.text)
image.height = int(getattr(item, imageLabel).Height.text)
bookInfo.images[imageLabel] = image
bookInfos.append(bookInfo)
return bookInfos
def getXmls():
xmls = []
for i in range(0, 1440+1, 10):
path = 'xmls/{}.xml'.format(i)
with open(path, 'r') as f:
xml = f.read()
xmls.append(xml)
return xmls
def main():
xmls = getXmls()
start = time.time()
bookInfos = parseXmls(xmls)
end = time.time()
print('Anzahl der XML: {}'.format(len(xmls)))
print('Anzahl der Bücher: {}'.format(len(bookInfos)))
print('Zeit analysieren: {}Sekunden'.format(end - start))
if __name__ == '__main__':
main()
$ python parse_amazon_xml.py
Anzahl der XML: 145
Anzahl der Bücher: 1442
Zeit analysieren: 0.14079904556274414 Sekunden
Es waren 0,140 Sekunden. Ich verwende das lxml-Modul zum Parsen.
parse_amazon_xml.go
package main
import (
"fmt"
"github.com/PuerkitoBio/goquery"
"io/ioutil"
"strconv"
"strings"
"time"
)
type ImageInfo struct {
url string
width int
height int
}
type BookInfo struct {
asin string
title string
binding string
author string
publisher string
publicationDate string
images map[string]ImageInfo
}
func parseXmls(xmls []string) []BookInfo {
bookInfos := []BookInfo{}
for _, xml := range xmls {
dom, _ := goquery.NewDocumentFromReader(strings.NewReader(xml))
dom.Find("Item").Each(func(_ int, item *goquery.Selection) {
bookInfo := BookInfo{}
bookInfo.asin = item.Find("ASIN").Text()
attributes := item.Find("ItemAttributes").First()
if attributes.Length() > 0 {
bookInfo.title = attributes.Find("Title").Text()
bookInfo.binding = attributes.Find("Binding").Text()
bookInfo.author = attributes.Find("Author").Text()
bookInfo.publisher = attributes.Find("Publisher").Text()
bookInfo.publicationDate = attributes.Find("PublicationDate").Text()
}
imageLabels := []string{
"SmallImage",
"MediumImage",
"LargeImage",
}
images := map[string]ImageInfo{}
for _, imageLabel := range imageLabels {
xml := item.Find(imageLabel).First()
url := xml.Find("URL").Text()
width, _ := strconv.Atoi(xml.Find("Height").Text())
height, _ := strconv.Atoi(xml.Find("Width").Text())
image := ImageInfo{url, width, height}
images[imageLabel] = image
}
bookInfo.images = images
bookInfos = append(bookInfos, bookInfo)
})
}
return bookInfos
}
func getXmls() []string {
xmls := []string{}
for i := 0; i <= 1440; i += 10 {
path := fmt.Sprintf("xmls/%d.xml", i)
xml, _ := ioutil.ReadFile(path)
xmls = append(xmls, string(xml))
}
return xmls
}
func main() {
xmls := getXmls()
start := time.Now()
bookInfos := parseXmls(xmls)
end := time.Now()
fmt.Printf("Anzahl der XML: %d\n", len(xmls))
fmt.Printf("Anzahl der Bücher: %d\n", len(bookInfos))
fmt.Printf("Zeit analysieren: %f Sekunden\n", (end.Sub(start)).Seconds())
}
$ go run parse_amazon_xml.go
Anzahl der XML: 145
Anzahl der Bücher: 1442
Zeit analysieren: 0.180461 Sekunden
0,18 Sekunden. Es ist langsamer als Python. Ich benutze goquery zum Parsen.
Go ist mit einem einzelnen Thread langsamer, aber Go kann problemlos parallel ausgeführt werden. Vergleichen wir dies also ebenfalls. Die laufende CPU besteht aus 2 Kernen und 4 Threads. Schreiben Sie nur die Codeänderungen.
parse_amazon_xml_th.go
//Nehmen Sie einen Kanal als Argument
//Rückgabewert löschen
func parseXmls(result chan []BookInfo, xmls []string) {
...Ausgelassen, weil es das gleiche ist
//Gibt das Verarbeitungsergebnis an den Kanal zurück (ersetzte Rückgabe)
result <- bookInfos
}
//Teilen Sie ein XML-Array in num
func divideXmls(xmls []string, num int) [][]string {
xmlsNum := len(xmls)
size := xmlsNum / num
result := [][]string{}
for i := 0; i < num; i++ {
start := size * i
end := size * (i + 1)
if i == (num - 1) {
end = xmlsNum
}
result = append(result, xmls[start:end])
}
return result
}
func main() {
allXmls := getXmls()
//Teilen Sie xml in 4
divXmls := divideXmls(allXmls, 4)
start := time.Now()
result := make(chan []BookInfo)
//In 4 Threads ausführen
for _, xmls := range divXmls {
go parseXmls(result, xmls)
}
//Empfangen Sie Verarbeitungsergebnisse von Kanälen und kombinieren Sie sie zu einem
bookInfos := []BookInfo{}
for _, _ = range divXmls {
bookInfos = append(bookInfos, <-result...)
}
end := time.Now()
fmt.Printf("Anzahl der XML: %d\n", len(allXmls))
fmt.Printf("Anzahl der Bücher: %d\n", len(bookInfos))
fmt.Printf("Zeit analysieren: %f Sekunden\n", (end.Sub(start)).Seconds())
}
$ go run parse_amazon_xml_th.go
Anzahl der XML: 145
Anzahl der Bücher: 1442
Zeit analysieren: 0.084918 Sekunden
0,084 Sekunden. Es hat sich verdoppelt.
Implementierung | Geschwindigkeit |
---|---|
Python (lxml) | 0.140 Sekunden |
Go (goquery)1 Thread | 0.180 Sekunden |
Go (goquery)4 Fäden | 0.084 Sekunden |
Go nur durch parallele Ausführung (Es gibt keinen Vorteil von Go, es sei denn, es wird parallel ausgeführt)
Recommended Posts