Multithreading 在ipython/jupyter笔记本中运行单元格的新线程
有时运行单个单元格需要很长时间,当它运行时,我希望在同一个笔记本中编写和运行其他单元格,在相同的上下文中访问变量Multithreading 在ipython/jupyter笔记本中运行单元格的新线程,multithreading,ipython,ipython-notebook,jupyter,Multithreading,Ipython,Ipython Notebook,Jupyter,有时运行单个单元格需要很长时间,当它运行时,我希望在同一个笔记本中编写和运行其他单元格,在相同的上下文中访问变量 是否可以使用ipython magic,当它被添加到单元格中时,运行单元格将自动创建一个新线程,并在笔记本中使用共享的全局数据运行?这可能不是答案,而是指向它的方向。我没有看到这样的东西,但我对这个也很感兴趣 我目前的发现表明,人们需要定义自己的自定义细胞魔法。很好的参考资料是文档中的自定义单元格魔术部分,以及我将考虑的两个示例: memit:IPython的神奇内存使用率测试 演
是否可以使用ipython magic,当它被添加到单元格中时,运行单元格将自动创建一个新线程,并在笔记本中使用共享的全局数据运行?这可能不是答案,而是指向它的方向。我没有看到这样的东西,但我对这个也很感兴趣 我目前的发现表明,人们需要定义自己的自定义细胞魔法。很好的参考资料是文档中的自定义单元格魔术部分,以及我将考虑的两个示例:
- memit:IPython的神奇内存使用率测试
- 演示Python多线程与多处理:
##github.com/jupyter/ngcm tutorial/blob/master/Day-1/IPython%20Kernel/Background%20Jobs.ipynb
从IPython.lib将后台作业作为bg导入
jobs=bg.BackgroundJobManager()
def printfunc(间隔=1,重复次数=5):
对于范围内的n(重复次数):
睡眠时间(间隔)
打印('在后台…%i“%n”)
sys.stdout.flush()
打印('全部完成!')
sys.stdout.flush()
jobs.new('printfunc(1,3)')
jobs.status()
更新2:另一个选项:
从IPython.display导入显示
从ipywidgets导入IntProgress
导入线程
类应用程序(对象):
定义初始值(自,nloops=2000):
self.nloops=nloops
self.pb=IntProgress(description='Thread loops',min=0,max=self.nloops)
def启动(自):
显示(self.pb)
当self.pb.value
这是我想到的一个小片段
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.
%job [fetch_url(_) for _ in log_progress(urls, every=1)]
然后,您可以通过以下方式监控状态:
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
与基于小部件的进度条一起使用,如下所示:
jobs = jobs_manager()
%job [fetch_url(_) for _ in urls] # saves html file to disk
Starting job # 0 in a separate thread.
%job [fetch_url(_) for _ in log_progress(urls, every=1)]
人们甚至可以使用%job
而不是多处理
for chunk in get_chunks(urls, 3):
%job [fetch_url(_) for _ in log_progress(chunk, every=1)]
此代码存在一些明显的问题:
您不能在%job
中使用任意代码。例如,可以没有作业,也可以没有打印。所以我将其用于在硬盘上存储结果的例程
有时,kill_-thread
中的肮脏黑客攻击不起作用。我认为这就是为什么IPython.lib.backgroundjobs
在设计上没有这个功能的原因。如果线程正在执行一些系统调用,如睡眠
或读取
异常将被忽略
它使用线程。Python有GIL,因此%job
不能用于一些需要Python字节码的繁重计算
@minrk请你看看这个答案,看看这个解决方案是否还有我没有想到的其他问题?什么是“你不能使用任意代码”?我正在尝试制作一个后台作业,用从磁盘打开的图像更新屏幕。我还注意到,time.sleep
“完成”了线程。回答得真棒!多年来一直在寻找这样的东西