質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
並列処理

複数の計算が同時に実行される手法

Python 2.7

Python 2.7は2.xシリーズでは最後のメジャーバージョンです。Python3.1にある機能の多くが含まれています。

Q&A

解決済

2回答

3865閲覧

Python: 並列処理

i.natsuki

総合スコア20

並列処理

複数の計算が同時に実行される手法

Python 2.7

Python 2.7は2.xシリーズでは最後のメジャーバージョンです。Python3.1にある機能の多くが含まれています。

1グッド

1クリップ

投稿2016/09/17 07:30

任意の数までの中に存在する素数を表示するプログラムを書きました。
処理にかかった時間も表示するようにしてみました。

python

1# coding=utf-8 2from time import time 3 4num = int(input('Enter the integer: ')) 5prime = [] 6 7if __name__ == '__main__': 8 st = time() 9 for i in range(2,num+1): 10 isprime = True 11 for j in prime: 12 if i % j == 0: 13 isprime = False 14 break 15 if isprime: 16 prime.append(i) 17 18 print(prime) 19 print('{0} sec'.format(time() - st)) 20

100を入力した場合の結果

c:\python>python prime.py Enter the integer: 100 [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97] 0.00200009346008 sec

PCの性能があまりよくないので1000000などの大きな数字を入力すると、処理にとても長い時間がかかってしまいます。
そこでPythonの並列処理のための外部モジュールであるjoblibを使用してより高速に処理しようと思いました。

python

1# coding=utf-8 2 3from sklearn.externals.joblib import Parallel, delayed 4from time import time 5 6num = int(raw_input('Enter the integer: ')) 7st = time() 8array = [] 9prime = [2,] 10def makeprime(num): 11 isprime = True 12 for j in prime: 13 if num % j == 0: 14 isprime = False 15 break 16 if isprime: 17 prime.append(num) 18 return num 19 20if __name__ == ' __main__': 21 array = Parallel(n_jobs=-1)( [delayed(makeprime)(i) for i in range(3,num)] ) 22 23print(array) 24print('{0} sec'.format(time() - st)) 25

すると結果は

c:\python>prime2.py Enter the integer: 100 [] 0.000999927520752 sec

このようになってしまいました。
調べたり試行錯誤したり、僕にできることはすべてやったつもりなのですがうまくいきません。
よろしければ何が悪かったのかご教授していただきたいです。
こちらは私がjoblibについて質問させていただいたものです。

mit0223👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

まず、コンピューターの性能問題に対する取り組み方について一言、言わせてください。性能を上げたい→並列計算すれば上がると言うのは、私の長い経験からすると、素人的な発想です。並列計算してもせいぜいCPU の個数倍にしかなりません。殆どの場合は、ソフトウェアに性能的なバグが有り、それを治すことが先決です(数十倍、場合によっては数万倍に性能が上がります)。この問題でいうと、

  • (数学的)素数かどうか確かめるときに、小さい素数から順に確かめるのであれば、素数の2乗が対象の数を超えた時点で可能性はゼロなので途中で諦めることができます。プログラウで言うと、 j の2乗が iを超えた時点で break したほうが性能が上がるでしょう(この計算自信、毎回なので、この計算にコストはかかりますが、直感的には break したほうが安い)
  • (プログラミング的) prime.append が遅そうです→一般的に大きな配列は append のコストは高いので、これを linked list とかにする必要があると考えます
  • (プログラミング的) for i in range(N) では、サイズNの配列を生成するので、 Nが大きいとそれだけで性能が悪い→普通に i のインクリメントで実装されるべき

それで、バグとしては panda_bk さんが指摘している共有変数の問題がありますが、それ以前に前回の質問の解答で参考にされていたサイト によりますと、 Windows では、 if __name__ == ' __main__': の外側に実行コードを書いては行けないとのことですので、

print(array) print('{0} sec'.format(time() - st))

が if 文の中に含まれてない(=インデントされてない)のが問題だと思います。

また、結果として array を print していますが、素数の配列を印刷したいのであれば、 prime を印刷しなければなりません。

さらに、 prime を共有変数にしたとして、上記にも書いたように、ある数 N が素数であるかどうか確かめるためにはN の平方根までの素数がわかっている必要があり、並列実行において、それが保証されていないので、単に joblib で並列計算するのではだめだと思います→スケジューリングが必要です。

あと、 print(array) は Pararell の返却値を印刷します。素数の配列を印刷したいのであれば、 print(prime) でないとだめなのではないですか?

投稿2016/09/17 12:57

mit0223

総合スコア3401

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

i.natsuki

2016/10/03 07:43

コメントが大変遅れてしまってもうしわけありません。 大変わかりやすい説明ありがとうございます。
guest

0

primeという変数がプロセス間で共有できる変数となっていませんね。
従って、プロセス間でprime変数を正常にやり取り出来ない為に起きている現象ではないでしょうか。

変数の定義を以下の様に書き換えてみるのは如何でしょう?

Python

1from multiprocessing import Manager 2〜省略〜 3manager = Manager() 4prime = manager.list()

また、並列化した際、そのままだと結果値が順不同になります。
順序を気にされる場合は最後のprintの前にsortを入れてやると良いかも知れません。
(ただし、それをする場合は当然ですが実行速度に悪影響が出ます。)

Python

1prime.sort() 2print(prime)

補足:
公式は推奨していない様ですが、multiprocessing.Arrayを使ったやり方でも同様に共有変数が定義できます。
参考ページ

投稿2016/09/17 11:32

panda_bk

総合スコア99

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問