我正在尝试基于 ipythonblocks 创建一些简单的异步执行动画,并且我正在尝试使用clear_output()
后跟一个grid.show()
.
对于文本输出,该技术的基础在线程 IPython Notebooks 的每个单元格输出中进行了讨论,因此我的简单假设是使用相同的方法来隔离 HTML 输出。由于我想用更新后的 HTML 版本反复替换网格,因此我尝试使用它clear_output()
来确保只显示一个网格副本。
我验证了这种提议的技术适用于以下单元格的文本输出。首先是上下文管理器。
import sys
from contextlib import contextmanager
import threading
stdout_lock = threading.Lock()
n = 0
@contextmanager
def set_stdout_parent(parent):
"""a context manager for setting a particular parent for sys.stdout
(i.e. redirecting output to a specific cell). The parent determines
the destination cell of output
"""
global n
save_parent = sys.stdout.parent_header
# we need a lock, so that other threads don't snatch control
# while we have set a temporary parent
with stdout_lock:
sys.stdout.parent_header = parent
try:
yield
finally:
# the flush is important, because that's when the parent_header actually has its effect
n += 1; print("Flushing", n)
sys.stdout.flush()
sys.stdout.parent_header = save_parent
然后是测试代码
import threading
import time
class timedThread(threading.Thread):
def run(self):
# record the parent (uncluding the stdout cell) when the thread starts
thread_parent = sys.stdout.parent_header
for i in range(3):
time.sleep(2)
# then ensure that the parent is the same as when the thread started
# every time we print
with set_stdout_parent(thread_parent):
print(i)
timedThread().start()
这提供了输出
0
Flushing 1
1
Flushing 2
2
Flushing 3
所以我修改了代码以清除循环之间的单元格。
import IPython.core.display
class clearingTimedThread(threading.Thread):
def run(self):
# record the parent (uncluding the stdout cell) when the thread starts
thread_parent = sys.stdout.parent_header
for i in range(3):
time.sleep(2)
# then ensure that the parent is the same as when the thread started
# every time we print
with set_stdout_parent(thread_parent):
IPython.core.display.clear_output()
print(i)
clearingTimedThread().start()
正如预期的那样,单元格的输出区域被反复清除,并最终读取
2
Flushing 6
因此,我认为在使用 ipythonblocks 时使用相同的技术来清除单元格的输出区域是安全的。唉,没有。这段代码
from ipythonblocks import BlockGrid
w = 10
h = 10
class clearingBlockThread(threading.Thread):
def run(self):
grid = BlockGrid(w, h)
# record the parent (uncluding the stdout cell) when the thread starts
thread_parent = sys.stdout.parent_header
for i in range(10):
# then ensure that the parent is the same as when the thread started
# every time we print
with set_stdout_parent(thread_parent):
block = grid[i, i]
block.green = 255
IPython.core.display.clear_output(other=True)
grid.show()
time.sleep(0.2)
clearingBlockThread().start()
确实会产生所需的最终状态(带有绿色对角线的黑色矩阵),但中间步骤不会出现在单元格的输出区域中。稍微复杂一点(?)这个例子是在 Python 3 上运行的。在发布之前检查我发现预期的行为(一个简单的动画)实际上确实发生在 Python 2.7 下。因此,我想问这是否是我需要报告的问题。