1つのセルを実行するのに時間がかかる場合があります。実行中に、同じコンテキストで変数にアクセスし、同じノートブックで他のセルを作成して実行したいと思います。
セルに追加されたときにセルを実行すると自動的に新しいスレッドが作成され、ノートブックの共有グローバルデータで実行されるように使用できるipythonマジックはありますか?
それは答えではないかもしれませんが、むしろそれへの方向性です。そんなものは見たことがありませんが、やはり興味があります。
私の現在の調査結果は、それを定義する必要があることを示唆しています独自のカスタムセルマジック。ドキュメントのカスタムセルマジックセクションと私が検討する2つの例が適切なリファレンスです。
どちらのリンクも、コードをスレッドにラップします。それが出発点になるかもしれません。
UPDATE:githubのngcm-tutorialにバックグラウンドジョブクラスの説明があります
##github.com/jupyter/ngcm-tutorial/blob/master/Day-1/IPython%20Kernel/Background%20Jobs.ipynb
from IPython.lib import backgroundjobs as bg
jobs = bg.BackgroundJobManager()
def printfunc(interval=1, reps=5):
for n in range(reps):
time.sleep(interval)
print('In the background... %i' % n)
sys.stdout.flush()
print('All done!')
sys.stdout.flush()
jobs.new('printfunc(1,3)')
jobs.status()
UPDATE 2:別のオプション:
from IPython.display import display
from ipywidgets import IntProgress
import threading
class App(object):
def __init__(self, nloops=2000):
self.nloops = nloops
self.pb = IntProgress(description='Thread loops', min=0, max=self.nloops)
def start(self):
display(self.pb)
while self.pb.value < self.nloops:
self.pb.value += 1
self.pb.color = 'red'
app = App(nloops=20000)
t = threading.Thread(target=app.start)
t.start()
#t.join()
ここに私が思いついた小さなスニペットがあります
def jobs_manager():
from IPython.lib.backgroundjobs import BackgroundJobManager
from IPython.core.magic import register_line_magic
from IPython import get_ipython
jobs = BackgroundJobManager()
@register_line_magic
def job(line):
ip = get_ipython()
jobs.new(line, ip.user_global_ns)
return jobs
IPython組み込みモジュールIPython.lib.backgroundjobs
を使用します。そのため、コードは小さくシンプルであり、新しい依存関係は導入されていません。
私はそれを次のように使用します:
jobs = jobs_manager()
%job [fetch_url(_) for _ in urls] # saves html file to disk
Starting job # 0 in a separate thread.
次に、次の方法で状態を監視できます。
jobs.status()
Running jobs:
1 : [fetch_url(_) for _ in urls]
Dead jobs:
0 : [fetch_url(_) for _ in urls]
ジョブが失敗した場合は、スタックトレースを検査できます
jobs.traceback(0)
仕事を殺す方法はありません。だから私はこの汚いハックを注意深く使います:
def kill_thread(thread):
import ctypes
id = thread.ident
code = ctypes.pythonapi.PyThreadState_SetAsyncExc(
ctypes.c_long(id),
ctypes.py_object(SystemError)
)
if code == 0:
raise ValueError('invalid thread id')
Elif code != 1:
ctypes.pythonapi.PyThreadState_SetAsyncExc(
ctypes.c_long(id),
ctypes.c_long(0)
)
raise SystemError('PyThreadState_SetAsyncExc failed')
与えられたスレッドでSystemError
を発生させます。だから仕事を殺すために
kill_thread(jobs.all[1])
実行中のすべてのジョブを強制終了するには
for thread in jobs.running:
kill_thread(thread)
ウィジェットベースのプログレスバーで%job
を使用したい https://github.com/alexanderkuk/log-progress このように:
%job [fetch_url(_) for _ in log_progress(urls, every=1)]
http://g.recordit.co/iZJsJm8BOL.gif
%job
の代わりにmultiprocessing.TreadPool
を使用することもできます。
for chunk in get_chunks(urls, 3):
%job [fetch_url(_) for _ in log_progress(chunk, every=1)]
http://g.recordit.co/oTVCwugZYk.gif
このコードのいくつかの明らかな問題:
%job
で任意のコードを使用することはできません。たとえば、割り当てや印刷はできません。結果をハードドライブに保存するルーチンで使用します
kill_thread
のダーティハックが機能しない場合があります。 IPython.lib.backgroundjobs
が仕様上この機能を持たないのはそのためだと思います。スレッドがsleep
またはread
のようなシステムコールを実行している場合、例外は無視されます。
スレッドを使用します。 PythonにはGILがあるため、%job
はpythonバイトコードを取り込むいくつかの重い計算には使用できません