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

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

新規登録して質問してみよう
ただいま回答率
85.47%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

711閲覧

関数を並列化する方法が分からない

old.exe

総合スコア23

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2022/10/04 02:49

遺伝的アルゴリズムで巡回セールスマン問題を解くプログラムを作りました。このプログラムの一部を並列化したいのですが、モジュールがthreading、multiprocessing、asyncioなどたくさんあり、どれをどう使用すべきか分かりません。以下、コードになります。この中でpfga()という関数を並列化したいです。

python

1import random 2import math 3import csv 4import copy 5import time 6 7 8 9def read_tspfile(): 10 """ 11 tspファイルを読み込み、都市の座標(float型)を 12 [[都市番号,X,Y],[...],...] の形で返す 13 """ 14 def str2float(cities): 15 data = [[0]]*len(cities) 16 for i in range(len(cities)): 17 city = [0]*len(cities[i]) 18 data[i] = city 19 try: 20 for j in range(len(cities[i])): 21 data[i][j] = float(cities[i][j]) 22 except: 23 data[i]*=0 24 continue 25 data2 = list(filter(None,data)) 26 return data2 27 28 def remove_blank(cities): 29 for i in range(len(cities)): 30 for j in range(len(cities[i])): 31 try: 32 cities[i].remove('') 33 except: 34 continue 35 36 with open("att48.tsp","r") as fin: 37 data = [city.split(' ') for city in fin.read().splitlines()] 38 remove_blank(data) 39 cities_data = str2float(data) 40 return cities_data 41 42 43 44cities_data = read_tspfile() 45population = [] # [[経路],[経路],[経路]...[経路]] 46cities = [] # Cityオブジェクトを入れるリスト 47CITIES_N = len(cities_data) # 都市数 48 49 50 51class City: 52 def __init__(self,num,X,Y): 53 self.num = num 54 self.X = X 55 self.Y = Y 56 57 58 59class Route: 60 def __init__(self): 61 self.distance = 0 62 63 # 経路を作成(重複なしのランダム) 64 self.citynums = random.sample(list(range(CITIES_N)),CITIES_N) 65 66 67 def calc_distance(self): 68 """ citynumsリストの各都市間の距離の総和を求める """ 69 self.distance = 0 70 for i,num in enumerate(self.citynums): 71 """ 72 1つ前の都市との距離を計算 73 i=0のとき、i-1は最後の都市(最後の都市からスタートへの距離) 74 """ 75 self.distance += math.dist((cities[num].X, 76 cities[num].Y), 77 (cities[self.citynums[i-1]].X, 78 cities[self.citynums[i-1]].Y)) 79 return self.distance 80 81 82def copy_route(route): 83 return copy.deepcopy(route) 84 85 86def mutate(c1,c2): 87 if random.random() > 0.5: 88 select_num = [i for i in range(len(c1.citynums))] 89 select_index = random.sample(select_num, 2) 90 91 a = c1.citynums[select_index[0]] 92 b = c1.citynums[select_index[1]] 93 c1.citynums[select_index[1]] = a 94 c1.citynums[select_index[0]] = b 95 96 else: 97 select_num = [i for i in range(len(c2.citynums))] 98 select_index = random.sample(select_num, 2) 99 100 a = c2.citynums[select_index[0]] 101 b = c2.citynums[select_index[1]] 102 c2.citynums[select_index[1]] = a 103 c2.citynums[select_index[0]] = b 104 105 return c1,c2 106 107 108 109def crossover(p1, p2): 110 # 子の遺伝子情報 111 c1 = copy_route(p1) 112 c2 = copy_route(p2) 113 # 切り離す位置をランダムに選択 114 index = random.randint(1,len(cities_data)-2) 115 # indexの前までは自身の経路 116 #indexの後からは相方のリスト(index前の都市と重複しないように) 117 fragment_c1 = c1.citynums[:index] 118 fragment_c2 = c2.citynums[:index] 119 120 notinslice_c1 = [X for X in fragment_c2 if X not in c1.citynums] 121 notinslice_c2 = [X for X in fragment_c1 if X not in c2.citynums] 122 #リストを合体 123 c1.citynums += notinslice_c1 124 c2.citynums += notinslice_c2 125 126 mutated_c1, mutated_c2 = mutate(c1,c2) 127 128 return mutated_c1,mutated_c2 129 130 131def pfga(): 132 133 # 2未満なら追加。これだけだとランダムに2こ取り出す動作でエラー吐く。別途初期集団は作っておく 134 if len(population) < 2: 135 population.append(Route()) 136 137 # ランダムに2個取り出す 138 p1 = population.pop(random.randint(0, len(population)-1)) 139 p2 = population.pop(random.randint(0, len(population)-1)) 140 141 # 子を作成 142 c1, c2 = crossover(p1,p2) 143 144 if p1.calc_distance() < p2.calc_distance(): 145 p_good = p1 # 短い経路(優秀) 146 p_bad = p2 # 長い経路(淘汰される) 147 else: 148 p_good = p2 149 p_bad = p1 150 if c1.calc_distance() < c2.calc_distance(): 151 c_good = c1 152 c_bad = c2 153 else: 154 c_good = c2 155 c_bad = c1 156 157 if c_bad.calc_distance() <= p_good.calc_distance(): 158 # 子2個体がともに親の2個体より良かった場合 159 # 子2個体及び適応度の良かった方の親個体計3個体が局所集団に戻り、局所集団数は1増加する。 160 population.append(c1) 161 population.append(c2) 162 population.append(p_good) 163 elif p_bad.calc_distance() <= c_good.calc_distance(): 164 # 子2個体がともに親の2個体より悪かった場合 165 # 親2個体のうち良かった方のみが局所集団に戻り、局所集団数は1減少する。 166 population.append(p_good) 167 elif p_good.calc_distance() <= c_good.calc_distance() and p_bad.calc_distance() >= c_good.calc_distance(): 168 # 親2個体のうちどちらか一方のみが子2個体より良かった場合 169 # 親2個体のうち良かった方と子2個体のうち良かった方が局所集団に戻り、局所集団数は変化しない。 170 population.append(c_good) 171 population.append(p_good) 172 elif c_good.calc_distance() <= p_good.calc_distance() and c_bad.calc_distance() >= p_good.calc_distance(): 173 # 子2個体のうちどちらか一方のみが親2個体より良かった場合 174 # 子2個体のうち良かった方のみが局所集団に戻り、全探索空間からランダムに1個体選んで局所集団に追加する。局所集団数は変化しない。 175 population.append(c_good) 176 population.append(Route()) 177 else: 178 raise ValueError("not comming") 179 180 181# 時間計測開始 182start = time.perf_counter() 183 184 185# citiesに読み込んだ座標を持つCityオブジェクトを入れる 186for i in range(CITIES_N): 187 cities.append(City(cities_data[i][0], 188 cities_data[i][1], 189 cities_data[i][2])) # num,X,Yの順 190 191 192# populationに個体を追加 193for i in range(2): 194 population.append(Route()) 195 196 197best = random.choice(population) # 個体(経路) 198record_distance = best.calc_distance() # 距離 199gen = 0 # 世代カウント用 200 201 202with open('PfGA_result.csv','w') as fout: 203 204 csvout = csv.writer(fout) 205 result = [] 206 207 while True: 208 print(record_distance) 209 population.sort(key=Route.calc_distance) 210 distance1 = population[0].calc_distance() # 最短経路 211 212 213 if distance1 < record_distance: 214 record_distance = distance1 215 best = population[0] # 最短経路を更新 216 217 218 pfga() 219 220 221 gen+=1 222 if gen == 1 or gen%100 == 0: 223 data = [] 224 data.extend([record_distance]) 225 result.append(data) 226 if gen == 50000: 227 csvout.writerows(result) 228 print(best.citynums) 229 230 231 # 時間計測終了(秒) 232 end = time.perf_counter() 233 tim = end - start 234 print(tim) 235 break 236 237

以上になります。よろしければ回答お願いします。

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

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

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

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

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

guest

回答2

0

ベストアンサー

複数CPUを使って同時に処理することで時間短縮を図りたいと言うことなら、multiprocessing だけです。

他の2つは、1つの処理が待ちになっている間に他の処理を進めるという並列化です。例えばファイルを読み書きするプログラム(あるいはSQLを実行するとか、ネットワークアクセスをするとか)があったとすると、OSがディスク入出力中の間は、プログラムは入出力処理完了を待ったままですが、threadingやasyncioを使うとその間に他の処理を行うことが出来ます。同時に使うCPUは1つだけです。

投稿2022/10/04 03:09

otn

総合スコア84663

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

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

0

threading: メモリ(変数)共有、スレッドセーフな作りにする必要がある
multiprocessing: メモリ独立、プロセス間通信でデータをやりとり
asyncio: 非同期処理、並列実行ではない

https://docs.python.org/ja/3/library/threading.html#module-threading

アプリケーションにマルチコアマシンの計算能力をより良く利用させたい場合は、 multiprocessing モジュールや concurrent.futures.ProcessPoolExecutor の利用をお勧めします。 ただし、I/Oバウンドなタスクを並行して複数走らせたい場合においては、 マルチスレッドは正しい選択肢です。

投稿2022/10/04 03:06

編集2022/10/04 03:13
shiracamus

総合スコア5406

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問