【问题标题】:tcl - when to use package+namespace vs interp?tcl - 何时使用包+命名空间与 interp?
【发布时间】:2018-01-09 04:08:53
【问题描述】:

我刚从 TCL 开始,并试图了解如何最好地定义和集成模块。似乎在包+命名空间概念上投入了很多精力,但据我所知,interp 对于每一个可以想象的场景都更强大、更精简。特别是当涉及到隐藏和重命名程序时,全局命名空间中也缺少蠕变。使用包+命名空间的唯一原因似乎是因为“从前 Sun 这么说”。

我什么时候应该使用包+命名空间而不是 interp?

【问题讨论】:

  • 在大型应用程序中节省内存,当您对解释器的构造和销毁有性能问题时(比命名空间管理成本更高)。我建议您阅读文档并根据您的应用程序要求做出决定。应用程序是如此广泛,以至于立即驳回interpnamespace 是不明智的。一般情况下,interp 创建一个由主 interp 管理的从解释器。每个 interp 都有自己的命名空间。因此,您可能会通过创建 interps 来浪费资源。但是你的需求应该决定你使用什么。

标签: tcl


【解决方案1】:

命名空间和包一起工作。口译员是另一回事。

命名空间是 Tcl 中的小规模命名上下文。它可以包含命令、变量和其他命名空间。您可以通过本地名称 (foo) 或限定名称 (bar::foo) 来引用命名空间中的实体;如果限定名称以:: 开头,则它与(解释器)全局命名空间相关,并且可用于从解释器中的任何位置引用其命令或变量。 (FWIW,TclOO 对象系统广泛构建在命名空间之上;每个对象都有一个命名空间。)

是由某种库提供的一堆代码的高级概念。包具有抽象名称(名称​​不必须与库的实现在磁盘上的存储方式相对应)和不同的版本;如有必要,您可以要求特定版本,尽管大多数时候您不会打扰。包可以通过多种机制实现,但它们几乎都归结为sourceing 一些 Tcl 脚本和loading 一些 DLL。几乎所有包都声明了命令,并且通常鼓励它们将这些命令放在与包具有相同通用名称的命名空间中。但是,由于各种原因,相当多的旧包没有这样做,主要是为了与现有代码的兼容性。

解释器是 Tcl 中的安全上下文。默认情况下,Tcl 创建一个解释器(如果它在wish 中设置控制台窗口,则添加另一个)。一个解释器中的命名实体与另一个解释器中的命名实体完全不同,但有一些关键例外:

  1. 频道在所有解释器中都有通用名称。这意味着口译员可以谈论另一个口译员拥有的频道,但仅仅能够提及其名称并不能授予访问该频道的权限。 (stdinstdoutstderr 频道默认共享。)

  2. interp alias 命令可用于生成别名命令,这样在一个解释器中调用命令(别名)会导致另一个解释器中的命令(实现)被调用,所有参数安全地通过了。这允许一个解释器公开它希望另一个解释器访问的任何特殊调用而不会失去控制,但这些命令的实现取决于这些命令是否安全地处理这些参数。

安全解释器是一种默认情况下会分析出 Tcl 的不安全命令的解释器。 (例如opensocketsourceloadcd 等)创建安全子解释器的父解释器可以使用别名机制来添加所需的功能;它非常类似于 OS 系统调用,只是您可以轻松地创建自己的特定于应用程序的调用。

Tcl 的线程包旨在创建每个线程一个解释器(并且别名机制不能跨线程工作)。这意味着默认情况下共享资源的方式很少,线程间通信是通过队列消息传递来完成的。


通常,每个解释器最多需要一次包,并且建议您使用这些包来访问大多数第三方功能。命名空间相当轻量级,可用于各种事情,解释器被认为是昂贵的;许多相当彻底的生产级 Tcl 脚本只能与单个解释器一起使用。 (线程甚至比解释器更昂贵;最好将您创建的线程数与您希望施加的硬件负载相匹配,可能通过使用合适的线程池。)

【讨论】:

  • 基本上,解释器几乎不做任何类型的资源共享,但提供了实质性的安全保证,而命名空间只是命名范围,用于阻止代码意外踩到彼此的脚趾,这在大型脚本中非常有用.命名空间不是安全设备;解释器安全设备(以及程序中每个用户线程中操作的根源)。
  • 非常好的总结。我将不得不更多地研究这个线程的事情,似乎很重要。但是,与命名空间相比,interp alias 真的可以那么重吗?它不仅仅是底层的函数指针吗?为什么任何 Tcl 脚本只能与单个解释器一起工作?对于任何解释器,命名空间通常会导致更多的符号和更长的符号名称,所以我预计命名空间比解释器更糟糕。再次,这是新的。善待新人。
【解决方案2】:

模块的目的是提供模块化代码,即可以在模块编写者的知识和控制范围之外被应用程序轻松使用的代码,并且封装了它们自己的内部结构。

基于包命名空间和解释器的模块在封装方面可能同样出色,但要使基于解释器的模块能够很好地与任意应用程序配合使用并不容易(当然有可能)。

我自己的观点是解释器是应用程序级别的(我主要将它们用于用户输入和受控评估),而不是模块级别。命名空间和包都有它们的缺点,但在大多数情况下,它们会以最少的麻烦做他们所期望的事情。

我的建议是,如果您是为了自己的利益而编写模块并且解释器为您提供良好的服务,请务必使用它们。如果您编写的模块供其他人使用,可能包括您自己在 18 个月后使用,您应该坚持使用命名空间和包。

【讨论】:

  • 要让基于解释器的模块与任意应用程序兼容并没有那么容易”?你有什么简单的例子吗?可能会感兴趣:我对基于解释器的集成的看法是,任何脚本都在全局命名空间中定义,源代码到新的解释器中,并使用别名与其他模块集成。脚本本身不会创建解释器。
  • @Andreas:没有一个简单的例子可以充分说明执行的复杂性是如何增加的。解释器主要是一种阻碍和限制的机制(这在需要的地方很好)。除了受控评估之外,使用解释器可以轻松完成的所有事情都可以在没有它的情况下更简单地完成。对于您的模块的用户来说,它基于解释器使得它更难集成,也更难测试和调试。相反,命名空间旨在使模块更易于使用。至于包,即使你使用解释器,你也不能真正免除它们。
  • 我的结论正好相反。基于解释器的集成使集成器处于控制之中,而基于命名空间的集成器则使集成器依赖于模块提供者,遵循广泛的规则列表,例如命名空间名称的好选择,在全局命名空间中的污染有限。这些是专业解释器、con 命名空间的可靠示例。到目前为止,最接近的示例 pro 命名空间是线程处理时(请参阅 Donal 答案)。编程模式和经验几乎不是语言特征(尽管有价值的输入)。
  • @Andreas: 如果你觉得你作为一个自称是新手的你比我有 18 年的 Tcl 经验,总共近 40 年的编程经验更能理解这一点,请务必遵循你的信念. ;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多