- xml - AJAX/Jquery XML 解析
- 具有多重继承的 XML 模式
- .net - 枚举序列化 Json 与 XML
- XML 简单类型、简单内容、复杂类型、复杂内容
我们有一个用 Go 编写的监控代理,它使用许多 goroutines 从 WMI 收集系统指标。我们最近发现当 go 二进制文件在 Server 2016 或 Windows 10(也可能在其他使用 WMF 5.1 的操作系统上)上运行时,程序会泄漏内存。在为 reproduce the issue 创建最小测试用例之后似乎仅当您对 ole.CoInitializeEx 方法进行大量调用时才会发生泄漏(WMF 5.1 中可能发生了一些变化,但我们无法在同一系统上使用 python comtypes 包重现该问题)。
我们在应用程序中将 COINIT_MULTITHREADED 用于多线程单元 (MTA),我的问题是:因为我们从各种 goroutine 发出 OLE/WbemScripting 调用,我们是否需要在启动时只调用一次 ole.CoInitializeEx或者在每个 goroutine 中一次?我们的query code已经使用 runtime.LockOSThread以防止调度程序在不同的操作系统线程上运行该方法,但 MSDN 对 CoInitializeEx 的评论似乎表明它必须在每个线程上至少调用一次。我不知道有什么方法可以确保新的 goroutines 在已经初始化的操作系统线程上运行,所以多次调用 CoInitializeEx 似乎是正确的方法(并且在过去几年中运行良好)。
我们已经refactored the code在专门的后台工作程序上执行所有 WMI 调用,但我很想知道我们的原始代码是否应该在启动时仅使用一个 CoInitializeEx 而不是每个 goroutine 一次。
最佳答案
据我所知,由于 Win32 API 仅根据 native 操作系统线程定义,因此对 CoInitialize[Ex]()
的调用只会影响它完成的线程。
由于 Go 运行时使用自由 M×N 调度 goroutines 到 OS 线程,并且这些线程在运行时以对 goroutines 完全透明的方式根据需要创建/删除,唯一的方法是确保 CoInitialize[Ex]()
调用对其执行的 goroutine 有任何持久影响是首先通过调用 runtime.LockOSThread()
将该 goroutine 绑定(bind)到其当前操作系统线程并执行此操作对于每个打算进行 COM 调用的 goroutine。
请注意,这基本上在 goroutine 和 OS 线程之间创建了一个 1×1 映射,这违背了 goroutine 的大部分目的。所以假设你可能想考虑只让一个 goroutine 调用 COM 并监听 channel 上的请求,或者让一组这样的 worker goroutines 隐藏在另一个 goroutines 之后,后者会将客户的请求发送给 workers。
关于 COINIT_MULTITHREADED
的更新。
引用the docs :
Multi-threading (also called free-threading) allows calls to methods of objects created by this thread to be run on any thread. There is no serialization of calls — many calls may occur to the same method or to the same object or simultaneously. Multi-threaded object concurrency offers the highest performance and takes the best advantage of multiprocessor hardware for cross-thread, cross-process, and cross-machine calling, since calls to objects are not serialized in any way. This means, however, that the code for objects must enforce its own concurrency model, typically through the use of synchronization primitives, such as critical sections, semaphores, or mutexes. In addition, because the object doesn't control the lifetime of the threads that are accessing it, no thread-specific state may be stored in the object (in Thread Local Storage).
因此,基本上 COM 线程模型与线程本身的初始化无关,而是与 COM 子系统如何调用您在 COM 初始化线程上创建的 COM 对象的方法有关。
IIUC,如果您将 COM 初始化一个线程为 COINIT_MULTITHREADED
并在其上创建一些 COM 对象,然后将其引用传递给该对象的某个外部客户端,以便它能够调用该对象对象的方法,操作系统可以在您进程中的任何线程上调用这些方法。
我真的不知道这应该如何与 Go 运行时交互,所以我会从小处着手,使用带有 STA 模型的单线程,然后如果需要,可能会尝试让它变得更复杂。
另一方面,如果您只实例化外部 COM 对象而不实例化将他们的描述符转移到外面(看起来就是这样),线程模型不应该是相关的。也就是说,除非某些WUA API 中的代码会在您创建的 COM 对象上调用一些“类事件”方法已经实例化。
关于go - CoInitializeEx(COINIT_MULTITHREADED) 和使用 WMI 的协程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42545728/
在我的设置中,我试图有一个界面 Table继承自 Map (因为它主要用作 map 的包装器)。两个类继承自 Table - 本地和全局。全局的将有一个可变的映射,而本地的将有一个只有本地条目的映射。
Rust Nomicon 有 an entire section on variance除了关于 Box 的这一小节,我或多或少地理解了这一点和 Vec在 T 上(共同)变体. Box and Vec
我是一名优秀的程序员,十分优秀!