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

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

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

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

Q&A

0回答

943閲覧

Pythonでプログラム間でメモリを共有する方法

miyaa

総合スコア4

Python

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

1グッド

3クリップ

投稿2020/12/23 07:34

前提・実現したいこと

Pythonで機械学習をテストするコードを書いています。
データが十数GBあり、それを予めメモリにロードすることで高速化していますが、(コードを書き換えるなどした)異なるプログラムを同時実行するにはメモリ容量に限界があります。

そこでメモリにロードするプログラムと、そこにアクセスして機械学習を実行するプログラムに分離したいと考えていますが、この機能を実現する方法・コードサンプルはあるでしょうか。

ネットで調べても、同一のプログラムからマルチプロセスに分岐して共有メモリを実現する方法しか見つけられませんでした……。
よろしくお願いします。

環境:Python 3.6.9、Ubuntu 18.04.3 LTS

A_kirisaki👍を押しています

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

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

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

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

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

ppaul

2020/12/23 08:30

現状は、一つの仮想空間内にロード用プログラムとデータと学習プログラムがあり、それがメモリ容量の限界とのことですね。現在のCPUでは仮想空間のアドレス可能領域は256テラバイトのはずですので仮想空間が足りないことではなく、物理メモリが足りないことが問題なのではないですか。 ここで、二つのプロセス(仮想空間)を作ってメモリを共有するなどしても、物理メモリの不足は変わらないように思います。
meg_

2020/12/23 11:03

> マルチプロセスに分岐して共有メモリを実現する方法 それでは駄目なのですか?メモリを共有するということは並列処理ということですよね?
miyaa

2020/12/23 12:48

ppaul さん 現状は、ロード用と学習用がまとまったプログラムを動かしています。 物理メモリは96GBあるのですが、共用サーバなので無闇やたらと使うことができない状況です。 仮想メモリを使って複数動作させることはできますが、メモリの確保に失敗してプログラムが強制終了することがあります(OOM Killerに殺されます)。 meg_ さん 一度にすべての処理を開始するわけではなく、何度もプログラムを変えて試行する必要がある関係で、よくあるマルチプロセスの方法をそのまま使うことができません。
dodox86

2020/12/23 13:56

「mmapを使った共有メモリ」が最初に頭に浮かびますが、そういう視点というよりは、他プロセスからアクセス可能な共有メモリがあり、他プロセスは任意の時点で起動し、その共有メモリにアクセスしたいとのようなことでしょうか。
miyaa

2020/12/23 14:38

「他プロセスからアクセス可能な共有メモリがあり、他プロセスは任意の時点で起動し、その共有メモリにアクセスしたい」というのは、その通りです。 mmapはすみませんが使ったことがないので明確には答えられませんが、少し調べてわからなかった点があるので、以下のことをご存知でしたら教えてほしいです。 ・mmapをしてファイルを論理メモリにマッピングすると、主記憶にはデータがコピーされるのか。 ・(コピーされる場合)複数プログラムからmmapをした場合は複数のコピーが作成されるのか。 ・(コピーされない場合)補助記憶にアクセスするので遅延が発生しますよね?
dodox86

2020/12/24 02:36

> ・mmapをしてファイルを論理メモリにマッピングすると、主記憶にはデータがコピーされるのか。 主記憶、つまりRAMであるPCのメインメモリを指しているとして、そうです。ファイルの内容がメモリに展開され、mmapオブジェクトを介してアクセスするかたちになります。 > ・(コピーされる場合)複数プログラムからmmapをした場合は複数のコピーが作成されるのか。 mmapオブジェクトの生成方法によります。MAP_PRIVATEやMAP_SHAREDの指定で、プログラムごとのものか、複数プログラムで共有するひとつのものかが決まります。https://docs.python.org/ja/3/library/mmap.html > ・(コピーされない場合)補助記憶にアクセスするので遅延が発生しますよね? 前述のMAP_PRIVATEならプログラムそれぞれのmmmapオブジェクトになるので、結果的にロードの為の遅延は発生することになりますね。本コメント欄で提案したmmap(メモリマップファイル、メモリマップトファイル)はファイルアクセスに際してメモリ上に展開し、メモリ上の操作でファイルに最終的に結果をコミットすることができるというもので、そのメカニズムの中で共有メモリを実現でき、複数プロセス間で共有できるというだけです。そのメモリを示すmmapオブジェクトに対してはファイル操作のようなメソッド操作が伴うので、C言語のようにローレベルで構造体のイメージで操作できれば簡単ですが、pythonプログラムの中でシームレスに扱い続けるのはちょっと難しいかもしれません。更に、数十GBもの巨大データだとメインメモリから追い出されるだろうから、アクセスする位置によっては仮想記憶によりスワップアウトされる機会も増えそうです。しかし、巨大なデータに伴うスワップアウトによる遅延は避け得ないことであるはずです。
dodox86

2020/12/24 02:38

尚、私自身はそのような巨大なサイズの共有メモリは扱ったことはありません。OSの制限でできないかもしれません。
ppaul

2020/12/24 03:45

最初に考えなければならないのは、「予めメモリにロードすることで高速化」というのが成り立つかどうかです。 すべてのデータに最初から最後までアクセスするようなプログラムは、High-Performance LINPACKのようなベンチマークプログラム以外には滅多にありません。必要もなくメモリを圧迫するのは、スラッシングを引き起こして却って性能を落とすこともあります。 プログラムがデータ待ちでエラプスが大きい場合で、すべてのデータを一度に使わないのであれば、別スレッドを作って、データの読み込みと計算を重ね合わせることで性能が良くなることが良くあります。 読み込み1 読み込み2 読み込み3 読み込み4       計算1   計算2   計算3  計算4 というようなパイプライン処理をするのです。 pythonではやったことはありませんが、threadingモジュールを使うメモリ共有型並列処理で、lockとかsemaphoreを使って同期をとりながらやれば、それほど難しくないと思います。 threadingを使った場合は、読み込みの結果はpythonのオブジェクトになるので、他の手段を使った場合のような困難さはありません。 本当にすべてのデータを最初から最後までアクセスするようなプログラムを実行したいのであれば、システム管理者にお願いして使用メモリなどの制限や優先順位をあげてもらうのが筋です。
A_kirisaki

2020/12/24 05:28

データをもたせた Python プロセス立ち上げといて、そこに Python ソースコード流し込んで exec させるという邪悪な方法を思いつきました
miyaa

2020/12/24 05:40

dodox86 さん ありがとうございます。 mmapでMAP_SHAREDにしてどこまでできるか試してみます。 使用しているサーバをよく確認してみたらスワップ領域は小さめに設定されていたので、スワッピングの遅延は考えなくても良さそうです。 (機械学習に最適化するための設定だと思われますが、そのせいでメモリの確保に失敗していたようです。) ppaul さん 案をいただきありがとうございます。 並列でのパイプライン処理は確かにうまく使えば便利そうですね。 ただ、学習時のシャッフルがオンになっているので、次のデータを予測できないという問題があります。 A_kirisaki さん 作法としてはよろしくないですが、まあ、できなくはないのでしょうね。 デバッグも大変になるのでやりたくないですけど(笑)
dodox86

2020/12/24 05:44

> データをもたせた Python プロセス立ち上げといて、そこに Python ソースコード流し込んで exec させる A_kirisakiさんご提示の案、実用性は置いておくとしても、通常と逆の発想で技術的に面白いです。
ppaul

2020/12/25 11:52

A_kirisakiのアイデアの意味が良くわかりません。 pythonのexec関数のことなのだとすると、メモリ問題の解決策にはならないですね。 pythonのexecは、シェルのsourceコマンドのようなもので、文字列として受け取ったものをインタープリタが解析して実行する機能ですので、fork-execのexecとは無関係です。 それとも、pythonの中でexec系のシステムコールを発行しようという話なのでしょうか。
miyaa

2020/12/25 12:47

mmapを試してみましたが、mmapを呼び出してもデータは物理メモリにロードされないことがわかりました。 回答は受付中のままにしますが、これから年末ということもあって忙しくなりそうなので、この問題の解決は後回しにさせていただきます。 ppaul さん execのシステムコールを発行しない=同一のプロセスだからこそ、マルチスレッディングとexecを使うことで、共有メモリにアクセスしつつコードを動的に読み込んで実行できそうな気がするのですが、違うのですかね?
dodox86

2020/12/25 12:59

> mmapを呼び出してもデータは物理メモリにロードされない どのように検証されたか分かりませんが、実際の読み出し処理(プログラムによるアクセス)が開始しないと、そのアクセスしたい領域部分は物理メモリにロードされない可能性はあるかも、です。
A_kirisaki

2020/12/25 13:04

> ppaul さん Python の exec 関数は実行文脈としてオブジェクトを渡せる仕様なのでそこに巨大なデータと必要な関数群を備えたオブジェクトを渡して、サーバーとしてラップしプロセスとして立ち上げてコード送りつけたろ、って発想です。巨大なデータが読み込みのみならあわよくばマルチプロセス化も狙えるってスンポーです
miyaa

2020/12/25 16:38

インデックス(添字)を乱数で指定して読み込みを繰り返すプログラムを実行しましたが、メモリはほぼ消費されませんでした。 物理メモリへの実際のロードがセグメント単位で行われるとして、そのセグメントのサイズが小さかったために消費が少なかったという可能性は考えられますが、いまいちよく分かっていません。 こうなったら実際に導入して速度が出るかを確かめるしかないですが、そこに手を回す余裕は今はない、という状況ですので……。 また今度試してみます。
A_kirisaki

2020/12/26 06:12

メモリへのロード回数がダメなら一回ですませばすればいいじゃないその 2、ということで tmpfs で RAM ディスク化するのを思いつきました。バッファ介さずファイル(RAM ディスク)から直接読み込むように設定すればお手軽にオンメモリ化できるのでは
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問