from rest_framework.views import APIView from rest_framework.response import Response import gc class test(APIView): def post(self,request,*args,**kwargs): __test = self.request.data['test'] return Response(__test) del __test gc.collect()
DjangoでAPIを作成しています。returnの後に使用しない変数のオブジェクトを削除してガベージコレクションをしたいのですが、どのような方法があるでしょうか。
▽追記
みなさま回答ありがとうございました。WEBサイトの作成でメモリが足りなくなり、pythonのガベージコレクションを行うことで解決しようとしていました。そのあと調査を続けたところ、ApacheとMySQLのチューニングを行うことにより、メモリ不足を解決することができました。質問の件について、私の実力ではベストアンサーを選ぶことができないため、1ヵ月ほど様子を見て、グッドの数が多い方をベストアンサーにして質問を閉めさせていただきます。ありがとうございました。
以下のような質問にはグッドを送りましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
グッドが多くついた質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
下記のような質問は推奨されていません。
- 間違っている
- 質問になっていない投稿
- スパムや攻撃的な表現を用いた投稿
適切な質問に修正を依頼しましょう。
回答5件
2
returnの後にその関数内でなにかすることはできません。
使用しない変数のオブジェクトを削除
もし、そのオブジェクトが関数外で使われないのであれば、pythonが自動で消してくれるので不要です。
また、質問の「__test」が束縛されているオブジェクトは、returnで返しているので、もし消してしまうと受け取った側で使えなくなります。
ガベージコレクションをしたい
もし、どうしてもやりたいなら、returnの前にやることになるでしょう。
消したオブジェクトをちゃんと消すのが目的なら、前に書いたとおりです。
また、書いたとおりインタプリタが適切に実施してくれるので、プログラムから意識的にGCを呼ぶ必要は無いと思います。
投稿2022/12/01 07:10
総合スコア10458
1
decoratorを使うのが一番簡単だと思いました(処理を追いにくく悪評も多い気がしますが)。
コード
python
1import os 2import gc 3import psutil 4 5def print_memories(): 6 print(psutil.Process(os.getpid()).memory_info()) 7 8def gc_when_returned(func): 9 def wrapper(*args, **kwargs): 10 func(*args, **kwargs) 11 gc.collect() 12 print("gc collected.") 13 return wrapper 14 15def hoge(): 16 print("hoge()") 17 o = [x for x in range(1024 * 1024)] 18 print_memories() 19 20@gc_when_returned 21def hoge_with_gc(): 22 print("hoge_with_gc()") 23 o = [x for x in range(1024 * 1024)] 24 print_memories() 25 26print_memories() 27hoge() 28print_memories() 29hoge_with_gc() 30print_memories()
※psutilはpipで入れる必要があります
結果
うちの環境(ubuntu 20.04 python3.8.10)だと実行結果は以下のようになります。
text
1pmem(rss=12230656, vms=22401024, shared=6459392, text=2863104, lib=0, data=5971968, dirty=0) 2hoge() 3pmem(rss=54915072, vms=65384448, shared=6602752, text=2863104, lib=0, data=48955392, dirty=0) 4pmem(rss=12750848, vms=22605824, shared=6602752, text=2863104, lib=0, data=6176768, dirty=0) 5hoge_with_gc() 6pmem(rss=54648832, vms=68108288, shared=6602752, text=2863104, lib=0, data=51679232, dirty=0) 7gc collected. 8pmem(rss=20930560, vms=34029568, shared=6602752, text=2863104, lib=0, data=17600512, dirty=0)
今回の例を今回の環境で見ると、普通に戻っただけでも開放されているので、あまり期待した効果はないようです。他の環境(処理系/バージョン/プラットフォーム)でどうなるかは未知数なので、能動的なgc自体に意味がないかどうかは分かりません。
注意
gcは基本的に自動で行われますが、任意のタイミングで実施できます。個人的に考えている、能動的なgcの主な使用用途としては、大きなメモリを使った後長く忙しい処理が入るとき、その直前に確実にメモリを空けておきたいとか、メモリの少ない環境でこまめに手動でgcしておきたいとか(パラメータでも調整できるかも)、でしょうか。いずれにしても比較的負荷の高い作業なことに注意です。
投稿2022/12/06 05:12
総合スコア594
良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
このような回答には修正を依頼しましょう。
1
「returnの後に使用しない変数のオブジェクト」をローカルな名前空間から削除したとしても、それはDjangoがクライアントにレスポンスとして返し終わるまでは必要なオブジェクトであり続けます。
関数の終了後にガベージコレクションをしたとしても、レスポンスに必要なオブジェクトである限りガベージコレクションで回収の対象になるはずがありません。
また、これはX-Y問題であるように感じます。
質問のような考えを仮定するとしても、カベージコレクションに回収されなかった時に何か困ることが起きているのでしょうか?
その何か困ることの方を質問するべきです。
何も困っていないのなら何もする必要はないし、何か困っているならその困っていることを解決する手段が知りたいはずだからです。(そして回答者は何もする必要はないことに回答はしたくないし、困っていることが解決する手段を回答したいのです)
Responseを返却し終わった後に処理をさせる方法を探してみましたが、request_finishedシグナルに応じて毎回ガベージコレクションを走らせるくらいしかなさそうでした。これですとすべてのリクエストの後にガベージコレクションが走ってまうので現実的ではなさそうという感想です。
あとはResponseを継承して終了後に何かを実行するという案もあります。
破棄したいものが特別扱いされるように__init__
を共に実装すれば何かが解決するかもしれません。
どちらも何に困っているかが質問にない以上、直接の回答はできずアイディア止まりです。あしからず。
投稿2022/12/02 05:35
編集2022/12/02 05:41総合スコア10419
良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
このような回答には修正を依頼しましょう。
1
contextlib.ExitStack を利用して、Golang の defer
と同様な事ができます。
※ 今回の場合、test.defer()
メソッド内での処理は不要なものかと思います。
python
1from contextlib import ExitStack 2import gc 3 4class Response(): 5 def __init__(self, arg): 6 self.arg = arg 7 8class test(): 9 def defer(self, local_vars, name): 10 del local_vars[f'_{__class__.__name__}{name}'] 11 gc.collect() 12 print('defer done') 13 14 def post(self,*args,**kwargs): 15 with ExitStack() as stack: 16 __test = [1, 'Response value'] 17 stack.callback(self.defer, locals(), '__test') 18 19 print('return from post') 20 return Response(__test) 21 22if __name__ == '__main__': 23 t = test() 24 ret = t.post() 25 print(ret.arg) 26 27# return from post 28# defer done 29# [1, 'Response value']
投稿2022/12/01 08:49
編集2022/12/01 09:27総合スコア16234
良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
このような回答には修正を依頼しましょう。
1
python
1from rest_framework.views import APIView 2from rest_framework.response import Response 3import gc 4 5class test(APIView): 6 def post(self,request,*args,**kwargs): 7 8 __test = self.request.data['test'] 9 10 ret = Response(__test) 11 12 del __test 13 gc.collect() 14 return ret
ただし、ガベージコレクトは必要なときに走ってくれるので自分で走らせる意味は無いと思います。
投稿2022/12/01 07:12
編集2022/12/01 07:16総合スコア13048
良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
このような回答には修正を依頼しましょう。
関連した質問
解決済
回答2
クリップ0
更新
2023/01/26
ECDHで作成した公開鍵をpemファイルに保存する際の正しいエンコードとデコードを知りたい。
解決済
回答2
クリップ0
更新
2023/01/27
pythonでの画像編集(ガンマ変換)
受付中
回答5
クリップ0
更新
2023/01/13
Pythonでreturnの後に処理を実行したい
受付中
回答1
クリップ2
更新
2023/01/29
jsとgasによるdoPostとfetch間によるhtmlファイルの受け渡しについて
解決済
回答2
クリップ0
更新
2023/01/28
Go/TypeScriptでHelloと表示させたい
解決済
回答1
クリップ0
更新
2023/01/28
配列を特定のキー,階層にした状態で、JSON形式に変換したい
受付中
回答2
クリップ1
更新
2023/01/28
Vue.jsにおいて、親コンポーネントの値を動的に子コンポーネントにわたす方法を教えて下さい
同じタグがついた質問を見る
DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。
Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。
良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。
下記のような回答は推奨されていません。
このような回答には修正を依頼しましょう。