【问题标题】:Does VBA use a Global Interpreter Lock? Do all interpreted languages need one?VBA 是否使用全局解释器锁?所有解释语言都需要一个吗?
【发布时间】:2021-03-27 22:25:18
【问题描述】:

可以使用Application.Run 方法将 VBA 类(COM 对象)从一个托管 VBA 进程传递到另一个(例如,将 Excel.exe 的一个实例传递给另一个)。这意味着第二个进程(线程 2)将有权访问第一个进程(线程 1)中定义的代码。

因此,第二个线程可能会从线程 1 调用对象上的一个方法,该方法使用第一个线程的解释器运行,因此线程 1 的解释器同时从线程 1 和线程 2 调用。


这对任何人来说可能都不足为奇,但对我来说却是这样,因为 VBA 是作为单线程语言实现的(它都在宿主应用程序的 UI 线程中运行!)并且没有为您提供编写多线程代码的语法。基于此,我认为 VBA 解释器肯定不是线程安全的,并且不允许从其他线程执行。但显然你可以,而且我过去也将 VBA 对象传递给 python 库(我想它们在 python 解释器的单独线程上运行)。

那么它是如何完成的,VBA 是否有像 Python 一样的 GIL - 这意味着解释器一次只能由一个线程运行,或者还有其他事情发生吗?有什么方法可以检查吗?

【问题讨论】:

  • 不,VBA 依赖于它创建的 STA 单元提供的线程保证。来自工作线程(不是由 VBA 创建)的调用会自动封送到 VBA 主线程。实际上与 JavaScript 执行模型非常相似。
  • @HansPassant 所以同步来自阻塞线程 2 的 com 代理,直到它发布并接收来自线程 1 的消息?
  • 没错。

标签: vba multithreading mutex interpreter gil


【解决方案1】:

为了控制哪些线程可以访问 COM 对象上的方法(线程关联),COM 使用了套间。公寓是具有相同线程亲和性的对象的地方。公寓特定于单个流程。

VBA 对象具有高线程亲和性,它们“存在”在 STA(单线程单元)中。他们将接收来自始终是同一个线程的单个线程的调用。在 VBA 中,STA 中只有一个线程。 STA 旨在保护对象免受并发影响。当线程进入 STA(调用 CoInitializeEx)时,会创建一个隐藏窗口。当对 STA 中的对象进行调用时,会向隐藏的窗口发送一个窗口消息,然后使单元中的线程执行该调用。如果两个线程调用位于 STA 中的对象上的方法,则隐藏窗口将收到两条消息,并且一次只会处理一条消息,这意味着第二条被阻塞,直到第一次调用完成。简而言之,STA 中的对象不具有并发性。

来自另一个进程的调用不是直接调用。不同的公寓和线程。 COM 改为模拟同步调用。调用进程中的调用被暂停,然后在实际对象所在的进程中重放。 COM 旨在处理来自不同计算机的对象。模拟(或拦截)涉及代理和存根以及 COM 传输。

例如,如果进程 1 中的 VBA 线程 (T1) 使用进程 2 (T2) 中的 VBA 线程中创建的对象,则该对象的接口从 T2 的单元导出到 T1 的单元(接口已编组)。当 COM 编组接口时,它会在 T2 的单元中创建一个存根。存根代表调用方 - T1。编组的信息被传输,然后用于在 T1 的单元中创建(解组)对象的接口(代理)。在代理和存根之间设置通信。因此,T1 接收到一个代理,而不是真正的对象(它位于完全不同的内存空间中)。当 T1 调用代理上的方法时,COM 通过 stub 将调用转发给真实对象,等待调用完成并返回结果。

【讨论】:

    猜你喜欢
    • 2016-08-26
    • 2023-03-17
    • 2010-09-20
    • 1970-01-01
    • 1970-01-01
    • 2021-02-25
    • 2011-09-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多