func01は void の関数になっているが、
戻り値があるタイプにして、
特定の処理の時、
想定しているのは 制限時間が来たときの
カートの清算だが、
制限時間が来たときに、戻り値を
返して、呼び出し元から func02を実行する、
これだと、func01からfunc02への
移行を管理する関数が要るので、
あまり、かわらないのか
--------------------------------------------
サンプル01
class res_instance01 :
def __init__( self ):
self.state_event = threading.Event()
self.list_error_zero_division = []
def is_state_changed( self ) :
return self.state_event.is_set()
def notify_state_change( self ) :
self.state_event.set()
class task :
def __init__( self, res_instance ):
self.res_instance = res_instance
self.list_error_zero_division = []
self.bool_is_state_change = False
def func01( self ) :
#処理内容を記述
self.bool_is_state_change = True
while self.bool_is_state_change :
# 1から10までの整数をランダムに取得
num = random.randint(1, 4)
if num = 3 :
bool_is_state_change = False
break
self.res_instance.func02()
'''
このあたりの部分で、3の値でループを終了し、
func01内部から func02を実行している
-> 詳しくは知らないが、スタックに積みあがる
↓
func01は void の関数になっているが、
戻り値があるタイプにして、
特定の処理の時、
想定しているのは 制限時間が来たときの
カートの清算だが、
制限時間が来たときに、戻り値を
返して、呼び出し元から func02を実行する、
これだと、func01からfunc02への
移行を管理する関数が要るので、
あまり、かわらないのか
''
def func02( self ) :
# 処理内容を記述
pass
class Main :
def __init__( self ):
self.thread01 = None
self.task01 = task( self.res_instance )
def main01( self ) :
self.run_thread01()
def run_thread01( self ) :
self.thread01 = threading.Thread(
target=self.task01.func01,
)
self.thread01.start()
if __name__ == "__main__":
app = Main()
app.main01()
サンプル01のおわり
サンプル02
class res_instance01 :
def __init__( self ):
self.state_event = threading.Event()
self.list_error_zero_division = []
def is_state_changed( self ) :
return self.state_event.is_set()
def notify_state_change( self ) :
self.state_event.set()
class task :
def __init__( self, res_instance ):
self.res_instance = res_instance
self.list_error_zero_division = []
self.bool_is_state_change = False
def func01( self ) :
#処理内容を記述
self.bool_is_state_change = True
while self.bool_is_state_change :
# 1から10までの整数をランダムに取得
num = random.randint(1, 4)
if num = 3 :
self.res_instance.notify_state_change()
bool_is_state_change = False
def func02( self ) :
# 処理内容を記述
pass
class Main :
def __init__( self ):
self.thread01 = None
self.thread02 = None
self.monitoring_thread = None
self.res_instance = res_instance()
self.task01 = task( self.res_instance )
def main01( self ) :
self.run_monitoring_thread()
self.run_thread01()
def run_monitoring_thread( self ) :
self.monitoring_thread = threading.Thread(
target=self.state_monitoring,
)
self.monitoring_thread.start()
def state_monitoring( self ) :
while self.bool_is_monitoring :
if self.res_instance.is_state_changed()
self.thread02 = threading.Thread(
target=self.task01.func01,
)
self.thread02.start()
self.bool_is_monitoring = False
def run_thread01( self ) :
self.thread01 = threading.Thread(
target=self.task01.func01,
)
self.thread01.start()
def run_thread02( self ) :
self.thread02 = threading.Thread(
target=self.task01.func02,
)
self.thread02.start()
if __name__ == "__main__":
app = Main()
app.main01()
サンプル02のおわり
上記の2つのコードにはres_instanceのクラスの使い方などに
違いがありますが、
taskクラスでの一連の操作に区切りがあれば、
スレッドを分けたほうがいいのでしょうか?
メモリの使い方に差があるのでしょうか?
インスタンスメソッド内で、
インスタンスメソッドをコールすると、
前のメソッドのスコープがメモリに割り当てられた状態のまま
次のメソッドがスタックに積みあがる、
ということを chatGPTさんに教わったことがあるのですが・・・
### スレッドを分けるべきか?
スレッドを分けるかどうかは
**処理の独立性** によります。
#### ① シングルスレッド(スレッドを分けない)
もし、`task` クラスの一連の処理が
「順番に実行されるべきもの」であれば、
スレッドを分ける必要はありません。
例えば、`func01()` の処理が終わってから
`func02()` を呼ぶなら、
同じスレッド内で実行するほうがシンプルです。
#### ② マルチスレッド(スレッドを分ける)
一方で、`func01()` の処理が終わるのを待たずに
`func02()` を実行したいなら、
スレッドを分けることで並列処理が可能になります。
例えば、`func01()` が
`notify_state_change()` を呼び出し、
それを監視する `state_monitoring()` が
`func02()` を別スレッドで実行するのは、
非同期処理を意図した設計になっています。
サンプル02では、`func01()` で
`notify_state_change()` を呼び出し、
`state_monitoring()` が
新しいスレッド (`thread02`) で
`func02()` を呼び出すようになっており、
処理が並列化されています。
---
### メモリの使い方の違い
スレッドを分けた場合、
各スレッドは**独立したスタック**を持つため、
それぞれのスレッドが個別にメソッドを呼び出しても、
他のスレッドのスタックには影響を与えません。
ただし、スレッドを分けるとメモリ使用量が増える可能性があります。
- **スレッドを分けると**、
それぞれのスレッドが**独立したスタックを持つ**ため、
複数のスレッドを作ると**
スレッドごとのスタックメモリ**が消費されます。
- 一方、シングルスレッドなら、
**1つのスタックだけ**が使われるため、
メモリ使用量は抑えられます。
また、`res_instance` のような
**共有オブジェクト** を複数のスレッドから
同時にアクセスする場合、
**スレッドセーフを考慮する必要** があります。
例えば、`state_event` は
スレッド間で共有されているため、
複数のスレッドが同時にアクセスして
競合しないように注意が必要です。
---
### インスタンスメソッドを呼び出すと、
メソッドのスコープがスタックに積み上がる?
はい、基本的にはその理解で合っています。
- インスタンスメソッドの呼び出しでは、
**前のメソッドのスコープがメモリ上に残ったまま
次のメソッドが呼び出される** ため、
再帰呼び出しや長い処理のネストがあると、
スタックの使用量が増えます。
- しかし、スレッドを分けると
**別のスレッドのスタックに積まれる** ため、
**スレッドごとに独立して処理される** という違いがあります。
例えば、サンプル02では:
1. `func01()` 内で `notify_state_change()` を呼ぶ。
2. `notify_state_change()` が
`state_monitoring()` のループで検出される。
3. `state_monitoring()` が
`func02()` を**別スレッド**で呼び出す。
このとき、`func01()` のスタックと
`func02()` のスタックは
**別のスレッドで管理される** ため、
それぞれの処理が独立します。
---
### 結論
1. **処理が完全に独立しているならスレッドを分けるのが有効**
→ 例: `func01()` が `func02()` に
影響を与えずに並列処理できるなら、
スレッドを分けることでパフォーマンス向上の可能性あり。
2. **シンプルな処理ならスレッドを分ける必要なし**
→ 例: `func01()` の後に `func02()` を
**順番に**実行するなら、スレッドを分けるよりも
**シングルスレッドで呼び出すほうがメモリ効率が良い**。
3. **スレッドを分けるとメモリ消費は増える**
→ スレッドごとにスタックメモリを消費するため、
大量のスレッドを作るとメモリ負担が増す。
4. **インスタンスメソッド内で別のメソッドを呼ぶと、
[ メソッドのスコープはスタックに積み上がる**
→ ただし、**別スレッドなら別のスタックで管理される**。
5. **スレッドを分けるならスレッドセーフを考慮**
→ `res_instance` のような共有オブジェクトに
複数のスレッドがアクセスする場合は、
適切な同期処理 (`threading.Lock()` など) を検討する。
このように、スレッドを分けるかどうかは
「処理の独立性」と「メモリ使用量」とのバランスで
判断するのがポイントです。
コメント
コメントを投稿