python - 线程化 IPython 笔记本的每单元格输出

标签 python web-services web-applications ipython ipython-notebook

我不想将此作为一个问题提出来,因为对于一个相当出色的工具来说,这似乎是一个完全不合理的功能请求。但是,如果任何读者碰巧熟悉该架构,我很想知道潜在的扩展是否可行。

我最近写了一个笔记本,里面有一些简单的线程代码,只是想看看当我运行它时会发生什么。 https://gist.github.com/4562840 提供了笔记本代码(tl;dr 它启动了许多在 sleep 循环中打印的并行线程)。

通过在代码运行时按几次 SHIFT-RETURN,您可以观察到内核的任何输出都出现在当前单元格的输出区域,而不是运行代码的单元格的输出区域。

我想知道是否有可能,如果线程对于一个单元格是事件的,显示一个“刷新”按钮允许异步更新输出区域。理想情况下,如果在所有线程结束后(在最终更新后)单击刷新按钮,它会消失。

不过,这将取决于能够识别和拦截每个线程的打印输出并将其定向到特定单元格输出的缓冲区。那么,两个问题。

  1. 我相信 Python 2 打印语句的硬连接意味着 这种增强功能不能用标准解释器实现吗?

  2. Python 3 的前景是否更好? 层进入 IPython 内核中的 print() 堆栈?特别是对于那些没有通过 Python 链接到达这里的人,

  3. [没有人期待西类牙宗教裁判所] 更一般地说,你能指出(与语言无关的)例子吗 多个流被传送到一个页面?是否有任何既定的最佳实践 构建和修改 DOM 来处理这个问题?

最佳答案

更新:

Am I correct in believing the the hard-wiring of Python 2's print statement means that this enhancement can not be implemented with a standard interpreter?

不,打印语句的重要部分根本不是硬连线的。 print 只是写入 sys.stdout,它可以是任何具有 writeflush 方法的对象。 IPython 已经完全替换了这个对象,以便首先将标准输出发送到笔记本(见下文)。

Are the prospects for Python 3 any better, given that it's possible to sneak another layer into the print() stack inside the IPython kernel?and especially for those who didn't follow a Python link to get here,

不 - 覆盖 sys.stdout 是你所需要的,而不是打印本身(见上文、下文和其他地方)。 Python 3 在这方面没有任何优势。

[nobody expects the Spanish Inquisition] More generally, can you point to (language-agnostic) examples of multiple streams being delivered into a page?

当然 - IPython 笔记本本身。它使用消息 ID 和元数据来确定标准输出消息的来源, 反过来,这些消息应该在哪里结束。 下面,在我对一个显然没有人问过的问题的原始回答中,我展示了一个同时绘制来自线程并发运行的多个单元的输出的示例。

为了获得您想要的刷新行为,您可能需要做两件事:

  1. 将 sys.stdout 替换为您自己的对象,该对象使用 IPython 显示协议(protocol)发送带有您自己的线程标识元数据(例如 threading.current_thread().ident)的消息。这应该在上下文管理器中完成(如下所示),因此它只会影响您实际想要的打印语句。
  2. 编写一个 IPython js 插件来处理新格式的 stdout 消息,这样它们就不会立即绘制,而是存储在数组中,等待绘制。

原始答案(错误但相关的问题):

它依赖于一些恶作剧和私有(private) API,但这在当前的 IPython 中是完全可能的(它可能不会永远存在)。

这是一个示例笔记本:http://nbviewer.ipython.org/4563193

为此,您首先需要了解 IPython 如何将标准输出发送到笔记本。 这是通过用 OutStream 对象替换 sys.stdout 来完成的。 这会缓冲数据,然后在调用 sys.stdout.flush 时通过 zeromq 发送它, 它最终出现在浏览器中。

现在,如何将输出发送到特定的单元格。

IPython message protocol 使用“父” header 来标识哪个请求产生了哪个回复。 每次您要求 IPython 运行一些代码时,它都会设置各种对象的父 header (包括 sys.stdout), 以便它们的副作用消息与导致它们的消息相关联。 当你在线程中运行代码时,这意味着当前的 parent_header 只是最近的 execute_request, 而不是启动任何给定线程的原始线程。

考虑到这一点,这里有一个上下文管理器,它临时将 stdout 的父 header 设置为特定值:

import sys
from contextlib import contextmanager


stdout_lock = threading.Lock()

@contextmanager
def set_stdout_parent(parent):
    """a context manager for setting a particular parent for sys.stdout

    the parent determines the destination cell of output
    """
    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
            sys.stdout.flush()
            sys.stdout.parent_header = save_parent

而这里是一个Thread,在线程启动时记录parent, 并在每次打印语句时应用该父级, 所以它的行为就好像它还在原来的单元格中一样:

import threading

class counterThread(threading.Thread):
    def run(self):
        # record the parent 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

最后,一个笔记本将所有内容捆绑在一起, 带有显示实际并发打印到多个单元格的时间戳:

http://nbviewer.ipython.org/4563193/

关于python - 线程化 IPython 笔记本的每单元格输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14393989/

相关文章:

python - 在Python中读取原始以太网数据包的VLAN字段

python - 如何填写列中的第一个日期?

svn - 关于网页设计的版本控制最佳实践

unit-testing - 您如何对远程托管的 Web 应用程序进行单元测试?

python - 使用flask-wtf queryselectfield进行更具体的SQL查询

python - linode 上的 gunicorn 无法启动

android - 如何使用 Android 调用 Web 服务

spring - 以 Angular 更改日期输入字段格式

java - 是否可以更改 XSD 文件的限制,而无需 Web 服务消费者进行任何调整?

Eclipse Maven Web 应用程序 - 无法再在服务器上运行