VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > 数据分析 >
  • PyPy 和 CPython 的性能比较测试

最近我在维基百科上完成了一些数据挖掘方面的任务。它由这些部分组成:

解析enwiki-pages-articles.xml的维基百科转储;

把类别和页存储到MongoDB里面;

对类别名称进行重新分门别类。

我对CPython 2.7.3和PyPy 2b的实际任务性能进行了测试。我使用的库是:

redis 2.7.2

pymongo 2.4.2

此外CPython是由以下库支持的:

hiredis

pymongo c-extensions

测试主要包含数据库解析,所以我没预料到会从PyPy得到多大好处(何况CPython的数据库驱动是C写的)。

下面我会描述一些有趣的结果。

 

抽取维基页名

 

我需要在所有维基百科的类别中建立维基页名到page.id的联接并存储重新分配好的它们。最简单的解决方案应该是导入enwiki-page.sql(定义了一个RDB表)到MySQL里面,然后传输数据、进行重分配。但我不想增加MySQL需求(有骨气!XD)所以我用纯Python写了一个简单的SQL插入语句解析器,然后直接从enwiki-page.sql导入数据,进行重分配。

这个任务对CPU依赖更大,所以我再次看好PyPy。

/ time

PyPy 169.00s 用户态 8.52s 系统态 90% CPU

CPython 1287.13s 用户态 8.10s 系统态 96% CPU

我也给page.id->类别做了类似的联接(我笔记本的内存太小了,不能保存供我测试的信息了)。

 

从enwiki.xml中筛选类别

 

为了方便工作,我需要从enwiki-pages-articles.xml中过滤类别,并将它们存储相同的XML格式的类别。因此我选用了SAX解析器,在PyPy和CPython中都适用的包装器解析。对外的原生编译包(同事在PyPy和CPython 中) 。

代码非常简单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
class WikiCategoryHandler(handler.ContentHandler):
    """Class which detecs category pages and stores them separately
    """
    ignored= set(('contributor','comment','meta'))
 
    def __init__(self, f_out):
        handler.ContentHandler.__init__(self)
        self.f_out= f_out
        self.curr_page= None
        self.curr_tag= ''
        self.curr_elem= Element('root', {})
        self.root= self.curr_elem
        self.stack= Stack()
        self.stack.push(self.curr_elem)
        self.skip= 0
 
    def startElement(self, name, attrs):
        if self.skip>0 or namein self.ignored:
            self.skip+= 1
            return
        self.curr_tag= name
        elem= Element(name, attrs)
        if name== 'page':
            elem.ns= -1
            self.curr_page= elem
        else:  # we don't want to keep old pages in memory
            self.curr_elem.append(elem)
        self.stack.push(elem)
        self.curr_elem= elem
 
    def endElement(self, name):
        if self.skip>0:
            self.skip-= 1
            return
        if name== 'page':
            self.task()
            self.curr_page= None
        self.stack.pop()
        self.curr_elem= self.stack.top()
        self.curr_tag= self.curr_elem.tag
 
    def characters(self, content):
        if content.isspace():return
        if self.skip== 0:
            self.curr_elem.append(TextElement(content))
            if self.curr_tag== 'ns':
                self.curr_page.ns= int(content)
 
    def startDocument(self):
        self.f_out.write("<root>\n")
 
    def endDocument(self):
        self.f_out.write("<\root>\n")
        print("FINISH PROCESSING WIKIPEDIA")
 
    def task(self):
        if self.curr_page.ns== 14:
            self.f_out.write(self.curr_page.render())
 
 
class Element(object):
    def __init__(self, tag, attrs):
        self.tag= tag
        self.attrs= attrs
        self.childrens= []
        self.append= self.childrens.append
 
    def __repr__(self):
        return "Element {}".format(self.tag)
 
    def render(self, margin=0):
        if not self.childrens:
            return u"{0}<{1}{2} />".format(
                " "*margin,
                self.tag,
                "".join([' {}="{}"'.format(k,v)for k,vin {}.iteritems()]))
        if isinstance(self.childrens[0], TextElement)and len(self.childrens)==1:
            return u"{0}<{1}{2}>{3}</{1}>".format(
                " "*margin,
                self.tag,
                "".join([u' {}="{}"'.format(k,v)for k,vin {}.iteritems()]),
                self.childrens[0].render())
 
        return u"{0}<{1}{2}>\n{3}\n{0}</{1}>".format(
            " "*margin,
            self.tag,
            "".join([u' {}="{}"'.format(k,v)for k,vin {}.iteritems()]),
            "\n".join((c.render(margin+2)for cin self.childrens)))
 
class TextElement(object):
    def __init__(self, content):
        self.content= content
 
    def __repr__(self):
        return "TextElement" def render(self, margin=0):
        return self.content

相关教程