Vergleichen Sie die XML-Parsing-Geschwindigkeiten mit Python und Go

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.

Laden Sie xml herunter

Verwenden Sie zunächst die Amazon Product Advertising API, um die XML-Datei der Buchinformationen zu löschen und in einer Datei zu speichern.

get_books_xml.go

$ 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.

In Python ausführen

parse_amazon_xml.py

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.

Laufen Sie in Go

parse_amazon_xml.go

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.

Parallele Ausführung in Go

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

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.

Zusammenfassung

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

Vergleichen Sie die XML-Parsing-Geschwindigkeiten mit Python und Go
Python mit Go
Programmieren mit Python und Tkinter
Python und Hardware-Verwenden von RS232C mit Python-
Generieren Sie XML (RSS) mit Python
Python mit Pyenv und Venv
Verarbeiten Sie Feedly-XML mit Python.
Funktioniert mit Python und R.
Vergleichen Sie HTTP GET / POST mit cURL (Befehl) und Python (Programmierung).
Beispiel für das Parsen von HTTP GET und JSON mit Pfefferpython
Kommunizieren Sie mit FX-5204PS mit Python und PyUSB
Leuchtendes Leben mit Python und OpenCV
Roboter läuft mit Arduino und Python
Installieren Sie Python 2.7.9 und Python 3.4.x mit pip.
Neuronales Netzwerk mit OpenCV 3 und Python 3
Scraping mit Node, Ruby und Python
Scraping mit Python, Selen und Chromedriver
Kratzen mit Python und schöner Suppe
JSON-Codierung und -Decodierung mit Python
Hadoop-Einführung und MapReduce mit Python
[GUI in Python] PyQt5-Drag & Drop-
Vergleichen Sie DCGAN und pix2pix mit Keras
Lesen und Schreiben von NetCDF mit Python
Ich habe mit PyQt5 und Python3 gespielt
Lesen und Schreiben von CSV mit Python
Vergleichen Sie Python- und JavaScript-Array-Schleifen
Geschwindigkeitsvergleich der Python-XML-Perspektive
[Python] Parsen von zufällig generiertem XML [ElementTree]
Mehrfachintegration mit Python und Sympy
Verarbeiten Sie Pubmed .xml-Daten mit Python
Koexistenz von Python2 und 3 mit CircleCI (1.0)
Sugoroku-Spiel und Zusatzspiel mit Python
FM-Modulation und Demodulation mit Python
Kommunizieren Sie mit gRPC zwischen Elixir und Python
Datenpipeline-Aufbau mit Python und Luigi
Berechnen Sie das Standardgewicht und zeigen Sie es mit Python an
Überwachen Sie Mojo-Ausfälle mit Python und Skype
FM-Modulation und Demodulation mit Python Part 3
Verarbeiten Sie Pubmed .xml-Daten mit Python [Teil 2]
Python-Installation und Paketverwaltung mit pip
Verwenden von Python und MeCab mit Azure Databricks
Vergleichen Sie rohen TensorFlow mit tf.contrib.learn und Keras
POST verschieden mit Python und empfange mit Flask
Bilder mit Pupil, Python und OpenCV aufnehmen
Fraktal zum Erstellen und Spielen mit Python
Ein Memo mit Python2.7 und Python3 in CentOS
Versuchen wir es mit gRPC mit Go und Docker
Verwenden Sie PIL oder Pillow mit Cygwin Python
Erstellen und entschlüsseln Sie Caesar-Code mit Python
CentOS 6.4, Python 2.7.3, Apache, mod_wsgi, Django
Lesen und Schreiben von JSON-Dateien mit Python
Umgang mit "Jahren und Monaten" in Python
Ich habe Numba mit Python3.5 installiert und verwendet
Tweet-Analyse mit Python, Mecab und CaboCha
Verknüpfung von Python und JavaScript mit dem Jupiter-Notizbuch
Verkehrsüberwachung mit Kibana, ElasticSearch und Python
FM-Modulation und Demodulation mit Python Part 2
Mit Ruby (Rails) verschlüsseln und mit Python entschlüsseln
Laden Sie einfach mp3 / mp4 mit Python und youtube-dl herunter!
Betreiben Sie Haushaltsgeräte mit Python und IRKit