python虚拟机集锦(5)-字节码解释器 3.11(2)

PEP 554 Stdlib中的多个解释器

概述

自1.5版(1997年)以来,CPython一直支持同一流程中的多个解释器(AKA“子解释器”)。该功能已通过C-API提供。[c-api]子解释器在彼此相对隔离的情况下运行,这有助于新的并发替代方法。

本提案介绍了stdlib解释器模块。该模块为临时模块。它公开了C-API已经提供的子企业的基本功能,以及在解释器之间共享数据的新(基本)功能。

为避免事先出现任何混淆:该PEP与子企业之间停止共享GIL的任何努力无关。该提案最多允许用户利用GIL的任何工作成果。这里的立场是,将子企业暴露于Python代码是值得的,即使它们仍然共享GIL。

解释器模块The “interpreters” Module

解释器模块将添加到stdlib中。为了帮助扩展模块的作者,将在扩展Python文档中添加一个新页面。有关这两个方面的更多信息。

解释器模块将为子企业提供一个高级接口,并包装一个新的低级解释器(与线程模块相同)。

除了公开现有的(在CPython中)子解释器支持外,该模块还将提供一种在解释器之间共享数据的机制。该机制以“通道”为中心,类似于队列和管道。

请注意,对象不会在解释器之间共享,因为它们与创建它们的解释器绑定。相反,对象的数据在解释器之间传递。

最初,仅支持以下类型的共享:

没有一个

扫描二维码关注公众号,回复: 15230691 查看本文章

字节

字符串

整数

PEP 554通道

稍后将添加对其他基本类型(例如bool、float、Ellipsis)的支持。

解释器模块的API概述

下面是解释器模块的API概述。有关建议的类和函数的更深入解释,请参阅下面的“解释器”模块API部分。

list_all() -> [Interpreter]
获取所有现有解释器。
get_current() -> Interpreter
获取当前正在运行的解释器。
get_main() -> Interpreter
找到主解释器。
create(*, isolated=True) -> Interpreter
初始化一个新的(空闲的)Python解释器。
class Interpreter(id)
单个解释器
.id
解释器的ID(只读)。
.isolated
解释器的模式(只读)。
.is_running() -> bool
解释器当前是否正在执行代码?
.close()
完成并销毁解释器。
.run(src_str, /, *, channels=None)

在解释器中运行给定的源代码。

(这将阻止当前线程,直到完成。)
RunFailedError
基类RuntimeError
Interpreter.run()导致未捕获的异常。
is_shareable(obj) -> Bool
是否可以共享对象的数据解释器。
create_channel() -> (RecvChannel, SendChannel)
创建用于传递的新通道解释器之间的数据。
list_all_channels() -> [(RecvChannel, SendChannel)]

获取所有打开的频道。
class RecvChannel(id)
信道的接收端。
.id
频道的唯一ID。
.recv() -> object
从频道中获取下一个对象,

如果没有发送,等待。

.recv_nowait(default=None) -> object
类似recv(),但返回默认值

而不是等待。

class SendChannel(id)
信道的发送端。
.id
频道的唯一ID。
.send(obj)
将对象(即其数据)发送到

信道的接收端并等待。
.send_nowait(obj)

类似send(),但如果未收到则返回False。
ChannelError
基类 Exception

通道相关异常的基类。
ChannelNotFoundError
基类ChannelError
找不到标识的频道。
ChannelEmptyError
基类 ChannelError
通道意外为空。
ChannelNotEmptyError
基类 ChannelError
通道意外不为空。
NotReceivedError
基类 ChannelError
没有任何东西等待接收发送的对象。

示例

运行隔离代码

interp = interpreters.create()
print('before')
interp.run('print("during")')
print('after')

在线程中运行

interp = interpreters.create()
def run():
    interp.run('print("during")')
t = threading.Thread(target=run)
print('before')
t.start()
print('after')

预填充解释器

interp = interpreters.create()
interp.run(tw.dedent("""
    import some_lib
    import an_expensive_module
    some_lib.set_up()
    """))
wait_for_request()
interp.run(tw.dedent("""
    some_lib.handle_request()
    """))

处理异常

interp = interpreters.create()
try:
    interp.run(tw.dedent("""
        raise KeyError
        """))
except interpreters.RunFailedError as exc:
    print(f"got the error from the subinterpreter: {
      
      exc}")

重新引发异常

interp = interpreters.create()
try:
    try:
        interp.run(tw.dedent("""
            raise KeyError
            """))
    except interpreters.RunFailedError as exc:
        raise exc.__cause__
except KeyError:
    print("got a KeyError from the subinterpreter")

使用频道同步

interp = interpreters.create()
r, s = interpreters.create_channel()
def run():
    interp.run(tw.dedent("""
        reader.recv()
        print("during")
        """),
        shared=dict(
            reader=r,
            ),
        )
t = threading.Thread(target=run)
print('before')
t.start()
print('after')
s.send(b'')

共享文件描述符

interp = interpreters.create()
r1, s1 = interpreters.create_channel()
r2, s2 = interpreters.create_channel()
def run():
    interp.run(tw.dedent("""
        fd = int.from_bytes(
                reader.recv(), 'big')
        for line in os.fdopen(fd):
            print(line)
        writer.send(b'')
        """),
        shared=dict(
            reader=r,
            writer=s2,
            ),
        )
t = threading.Thread(target=run)
t.start()
with open('spamspamspam') as infile:
    fd = infile.fileno().to_bytes(1, 'big')
    s.send(fd)
    r.recv()

通过封送传递对象

interp = interpreters.create()
r, s = interpreters.create_channel()
interp.run(tw.dedent("""
    import marshal
    """),
    shared=dict(
        reader=r,
        ),
    )
def run():
    interp.run(tw.dedent("""
        data = reader.recv()
        while data:
            obj = marshal.loads(data)
            do_something(obj)
            data = reader.recv()
        """))
t = threading.Thread(target=run)
t.start()
for obj in input:
    data = marshal.dumps(obj)
    s.send(data)
s.send(None)

通过pickle传递对象

interp = interpreters.create()
r, s = interpreters.create_channel()
interp.run(tw.dedent("""
    import pickle
    """),
    shared=dict(
        reader=r,
        ),
    )
def run():
    interp.run(tw.dedent("""
        data = reader.recv()
        while data:
            obj = pickle.loads(data)
            do_something(obj)
            data = reader.recv()
        """))
t = threading.Thread(target=run)
t.start()
for obj in input:
    data = pickle.dumps(obj)
    s.send(data)
s.send(None)

运行模块

interp = interpreters.create()
main_module = mod_name
interp.run(f'import runpy; runpy.run_module({
      
      main_module!r})')

作为脚本运行(包括zip存档和目录)

interp = interpreters.create()
main_script = path_name
interp.run(f"import runpy; runpy.run_path({
      
      main_script!r})")

在线程池执行器中运行

interps = [interpreters.create() for i in range(5)]
with concurrent.futures.ThreadPoolExecutor(max_workers=len(interps)) as pool:
    print('before')
    for interp in interps:
        pool.submit(interp.run, 'print("starting"); print("stopping")'
    print('after')

猜你喜欢

转载自blog.csdn.net/AI_LX/article/details/128742426