検索
PyPyとCPythonの性能比較テストOct 18, 2016 pm 01:33 PM
cpythonpypypythonパフォーマンステスト

最近、Wikipedia でいくつかのデータ マイニング タスクを完了しました。これは次の部分で構成されます:

enwiki-pages-articles.xml の Wikipedia ダンプを解析する;

カテゴリとページを MongoDB に保存する;

カテゴリ名を再分類する。

実際のタスクで CPython 2.7.3 と PyPy 2b のパフォーマンスをテストしました。私が使用したライブラリは次のとおりです:

redis 2.7.2

pymongo 2.4.2

また、CPython は次のライブラリでもサポートされています:

hiredis

pymongo c-extensions

テストは主にデータベースの解析で構成されているため、 PyPy からどれだけのメリットが得られるかは予想していませんでした (CPython のデータベース ドライバーが C で書かれていることは言うまでもありません)。

以下にいくつかの興味深い結果について説明します。


Wikiページ名を抽出します


すべてのWikipediaカテゴリのpage.idへのWikiページ名の結合を作成し、再割り当てされたものを保存する必要があります。最も簡単な解決策は、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->category に対しても同様の結合を行いました (Iラップトップのメモリが小さすぎて、テスト用の情報を保持できません)。


enwiki からカテゴリをフィルターします。したがって、PyPy と CPython の両方で動作するラッパー パーサーである SAX パーサーを選択しました。外部ネイティブ コンパイル パッケージ (PyPy および CPython の同僚)。

コードは非常にシンプルです:

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 name in 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([&#39; {}="{}"&#39;.format(k,v) for k,v in {}.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&#39; {}="{}"&#39;.format(k,v) for k,v in {}.iteritems()]),
                self.childrens[0].render())
  
        return u"{0}<{1}{2}>\n{3}\n{0}</{1}>".format(
            " "*margin,
            self.tag,
            "".join([u&#39; {}="{}"&#39;.format(k,v) for k,v in {}.iteritems()]),
            "\n".join((c.render(margin+2) for c in 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

Element 要素と TextElement 要素にはタグと本文の情報が含まれており、それをレンダリングするメソッドを提供します。

以下は私が欲しいPyPyとCPythonの比較結果です。

/time

PyPy 2169.90s

CPython 4494.69s

PyPyの結果にはとても驚きました。

興味深いカテゴリのセットの計算

私はかつて、アプリケーションの 1 つのコンテキストで、コンピューティング カテゴリから派生したいくつかのカテゴリから始めて、興味深いカテゴリのセットを計算したいと考えていました。これを行うには、クラスを提供するクラス図、つまりサブクラス図を構築する必要があります。

構造クラスとサブクラスの関係図

このタスクは、MongoDB をデータ ソースとして使用し、構造を再配布します。アルゴリズムは次のとおりです:

for each category.id in redis_categories (it holds *category.id -> category title mapping*) do:
    title = redis_categories.get(category.id)
    parent_categories = mongodb get categories for title
    for each parent_cat in parent categories do:
        redis_tree.sadd(parent_cat, title) # add to parent_cat set title

このような疑似コードを書いて申し訳ありませんが、もっとコンパクトに見せたいのです。

つまり、このタスクはあるデータベースから別のデータベースにデータをコピーするだけです。ここでの結果は、MongoDB がウォームアップされた後に取得されます (データがウォームアップされていない場合、データに偏りが生じます。この Python タスクは CPU の約 10% しか消費しません)。タイミングは次のとおりです:

/time

PyPy 175.11s ユーザーモード 66.11s システムモード 64% CPU

CPython 457.92s ユーザーモード 72.86s システムモード 81% CPU

redis_tree (再配布ツリー) の走査


redis_tree データベースがある場合、残る唯一の問題は、[コンピューティング] カテゴリの下にあるすべての達成可能なノードを走査することです。ループトラバーサルを回避するには、訪問したノードを記録する必要があります。 Python のデータベースのパフォーマンスをテストしたかったので、コレクション列を再配布することでこの問題を解決しました。

/ time

PyPy 14.79s ユーザーモード 6.22s システムモード 69% CPU 30.322 合計

CPython 44.20s ユーザーモード 13.86s システムモード 71% CPU 1:20.91 合計

正直に言うと、このタスクにはいくつかのビルドも必要ですタブー リスト (禁止リスト) - 不要なカテゴリへの入力を避けるため。しかし、それはこの記事の要点ではありません。

結論

実施されたテストは、私の最終的な作業のプレビューにすぎません。それには一連の知識、つまりウィキペディアから適切なコンテンツを抽出して得た一連の知識が必要です。

私の単純なデータベース操作では、CPython と比較して PyPy のパフォーマンスが 2 ~ 3 倍向上しました。 (ここでは SQL パーサーはカウントしていません。約 8 回です)

PyPy のおかげで、私の仕事はより快適になりました - アルゴリズムを書き換えることなく Python を効率的にすることができ、PyPy は CPython のように CPU に負荷をかけませんでした。そのため、しばらくラップトップを通常どおりに使用できなくなりました(CPU 時間の割合を見てください)。

タスクはほぼすべてデータベース操作であり、CPython には高速化された乱雑な C 言語モジュールがいくつかあります。 PyPy はこれらを使用しませんが、結果はより高速です。

私の仕事はすべて多くのサイクルを必要とするので、PyPy を使用することに本当に興奮しています。

声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
Python 获取线程返回值的三种方式Python 获取线程返回值的三种方式Apr 13, 2023 am 10:43 AM

提到线程,你的大脑应该有这样的印象:我们可以控制它何时开始,却无法控制它何时结束,那么如何获取线程的返回值呢?今天就分享一下自己的一些做法。方法一:使用全局变量的列表,来保存返回值ret_values = [] def thread_func(*args): ... value = ... ret_values.append(value)选择列表的一个原因是:列表的 append() 方法是线程安全的,CPython 中,GIL 防止对它们的并发访问。如果你使用自定义的数据结构,在并

详细讲解Python之Seaborn(数据可视化)详细讲解Python之Seaborn(数据可视化)Apr 21, 2022 pm 06:08 PM

本篇文章给大家带来了关于Python的相关知识,其中主要介绍了关于Seaborn的相关问题,包括了数据可视化处理的散点图、折线图、条形图等等内容,下面一起来看一下,希望对大家有帮助。

详细了解Python进程池与进程锁详细了解Python进程池与进程锁May 10, 2022 pm 06:11 PM

本篇文章给大家带来了关于Python的相关知识,其中主要介绍了关于进程池与进程锁的相关问题,包括进程池的创建模块,进程池函数等等内容,下面一起来看一下,希望对大家有帮助。

Python自动化实践之筛选简历Python自动化实践之筛选简历Jun 07, 2022 pm 06:59 PM

本篇文章给大家带来了关于Python的相关知识,其中主要介绍了关于简历筛选的相关问题,包括了定义 ReadDoc 类用以读取 word 文件以及定义 search_word 函数用以筛选的相关内容,下面一起来看一下,希望对大家有帮助。

如何使用PyPy提高Python程序的性能如何使用PyPy提高Python程序的性能Aug 02, 2023 am 10:39 AM

如何使用PyPy提高Python程序的性能导语:Python作为一种高级编程语言,具有简洁、易读、易学的特点,因此得到了广泛的应用。然而,Python也因其解释执行的特点导致了运行速度较慢的问题。为了解决这个问题,PyPy应运而生。本文将介绍如何使用PyPy来提高Python程序的性能。一、什么是PyPy?PyPy是一种即时编译的Python解释器,通过即时

归纳总结Python标准库归纳总结Python标准库May 03, 2022 am 09:00 AM

本篇文章给大家带来了关于Python的相关知识,其中主要介绍了关于标准库总结的相关问题,下面一起来看一下,希望对大家有帮助。

Python数据类型详解之字符串、数字Python数据类型详解之字符串、数字Apr 27, 2022 pm 07:27 PM

本篇文章给大家带来了关于Python的相关知识,其中主要介绍了关于数据类型之字符串、数字的相关问题,下面一起来看一下,希望对大家有帮助。

分享10款高效的VSCode插件,总有一款能够惊艳到你!!分享10款高效的VSCode插件,总有一款能够惊艳到你!!Mar 09, 2021 am 10:15 AM

VS Code的确是一款非常热门、有强大用户基础的一款开发工具。本文给大家介绍一下10款高效、好用的插件,能够让原本单薄的VS Code如虎添翼,开发效率顿时提升到一个新的阶段。

See all articles

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

SublimeText3 Linux 新バージョン

SublimeText3 Linux 新バージョン

SublimeText3 Linux 最新バージョン

PhpStorm Mac バージョン

PhpStorm Mac バージョン

最新(2018.2.1)のプロフェッショナル向けPHP統合開発ツール

AtomエディタMac版ダウンロード

AtomエディタMac版ダウンロード

最も人気のあるオープンソースエディター

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

Eclipse を SAP NetWeaver アプリケーション サーバーと統合します。

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境