web-dev-qa-db-ja.com

Pythonモジュールのインポートの速度を向上させる

Pythonモジュールのインポートを高速化する方法についての質問は以前に尋ねられました( python "import"ローダー)の高速化 および Python-Speed Up Imports? )しかし、具体的な例がなく、受け入れられた解決策が得られていないため、ここでもう一度問題を取り上げますが、今回は具体的な例を示します。

私はPythonスクリプトを使用して、3D画像スタックをディスクからロードし、それを平滑化して、ムービーとして表示します。このスクリプトをシステムコマンドから呼び出して、すばやく表示したい場合にプロンプ​​トを表示します私のデータです。これは、MATLABに匹敵するため、データの平滑化にかかる700ミリ秒で問題ありません。ただし、モジュールのインポートにはさらに650ミリ秒かかります。したがって、ユーザーの観点からは、Pythonコードは半分の速度で実行されます。

これは私がインポートしている一連のモジュールです:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import scipy.ndimage
import scipy.signal
import sys
import os

もちろん、すべてのモジュールのインポートが同じくらい遅いわけではありません。主な犯人は次のとおりです。

matplotlib.pyplot   [300ms]
numpy               [110ms]
scipy.signal        [200ms]

私はfromを使用して実験しましたが、これはより速くはありません。 Matplotlibが主な原因であり、画面の更新が遅いという評判があるため、別の方法を探しました。 1つはPyQtGraphですが、インポートには550ミリ秒かかります。

私は、システムコマンドプロンプトではなくインタラクティブPythonセッションから関数を呼び出すことです。これは問題ありませんが、MATLABに似すぎているので、システムのプロンプトから私の機能を利用できるようにする優雅さ。

私はPython=に不慣れで、この時点でどのように進めるかわかりません。私は新しいので、提案されたソリューションを実装する方法に関するリンクをいただければ幸いです。理想的には、 m複数のMacマシンとLinuxマシン間でコードを移植できる必要があるため、シンプルなソリューションを探しています(全員ではありません!)。

36
RAAC

単純なサーバー/クライアントを構築し、サーバーは継続的にプロットを作成および更新し、クライアントは処理する次のファイルを通信するだけです。

socketモジュールのドキュメントの基本的な例に基づいて、簡単なサーバー/クライアントの例を書きました: http://docs.python.org/2/library/socket.html#example

ここにserver.pyがあります:

# expensive imports
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import scipy.ndimage
import scipy.signal
import sys
import os

# Echo server program
import socket

Host = ''                 # Symbolic name meaning all available interfaces
PORT = 50007              # Arbitrary non-privileged port
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((Host, PORT))
s.listen(1)
while 1:
    conn, addr = s.accept()
    print 'Connected by', addr
    data = conn.recv(1024)
    if not data: break
    conn.sendall("PLOTTING:" + data)
    # update plot
    conn.close()

そしてclient.py:

# Echo client program
import socket
import sys

Host = ''    # The remote Host
PORT = 50007              # The same port as used by the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((Host, PORT))
s.sendall(sys.argv[1])
data = s.recv(1024)
s.close()
print 'Received', repr(data)

サーバーを実行するだけです。

python server.py

これによりインポートが行われ、クライアントはソケットを介して、プロットする新しいファイルのファイル名を送信します。

python client.py mytextfile.txt

その後、サーバーはプロットを更新します。

私のマシンでインポートを実行すると0.6秒かかりますが、client.pyを実行すると0.03秒かかります。

17
Andrea Zonca

質問に対する実際の回答ではありませんが、Python 3.7および tuna (私の小さなプロジェクト)を使用してインポート速度をプロファイルする方法に関するヒント:

python3.7 -X importtime -c "import scipy" 2> scipy.log
tuna scipy.log

enter image description here

21
Nico Schlömer

代わりに、impを使用して、モジュールを手動でインポートできます。 ドキュメントはこちら を参照してください。

例えば、 import numpy as npはおそらく次のように書くことができます

import imp
np = imp.load_module("numpy",None,"/usr/lib/python2.7/dist-packages/numpy",('','',5))

これにより、python全体の参照から解放されますsys.pathで目的のパッケージを見つけます。

以下も参照してください。

手動でのgtkのインポートは失敗します:モジュールが見つかりません

5
phil294

1.35秒は長くはありませんが、「クイックチェック」で半分に慣れているとしたら、おそらくそうでしょう。

Andreaは単純なクライアント/サーバーのセットアップを提案していますが、スクリプトのごくわずかな変更を呼び出して、作業中はコンソールウィンドウを開いたままにしておくことができるように思えます。

  • インポートを実行し、入力を待機するスクリプトを呼び出します
  • コンソールウィンドウを最小化し、作業に切り替えます。
  • もう一度コンソールを選択します
  • スクリプトに何らかの入力を提供する
  • インポートのオーバーヘッドなしで結果を受け取る
  • 喜んで入力を待っている間に、スクリプトから再び切り替えます。

私はあなたのスクリプトが毎回同じであると思います、つまりあなたは毎回それに画像スタックの場所や特定のコマンドを与える必要はありません(しかし、これらも同様に簡単です!)。

RAACの_Script.pyの例:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import scipy.ndimage
import scipy.signal
import sys
import os

print('********* RAAC\'s Script Now Running *********')

while True: # Loops forever
    # Display a message and wait for user to enter text followed by enter key.
    # In this case, we're not expecting any text at all and if there is any it's ignored
    input('Press Enter to test image stack...')

    '''
    *
    *
    **RAAC's Code Goes Here** (Make sure it's indented/inside the while loop!)
    *
    *
    '''

スクリプトを終了するには、コンソールウィンドウを閉じるか、Ctrl + Cキーを押します。

私はこれを可能な限り単純にしましたが、うまく終了したり、入力に基づいて少し異なることをしたりするなどの処理に余分なものはほとんど必要ありません。

1
ElectricWarr