gpt4 book ai didi

go - CoInitializeEx(COINIT_MULTITHREADED) 和使用 WMI 的协程

转载 作者:数据小太阳 更新时间:2023-10-29 03:13:59 24 4
gpt4 key购买 nike

我们有一个用 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/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com