.NET 4 任务并行库可以使用 COM 对象吗?
这是一个“这可能吗?如果可以的话,你能给我一个简单的例子吗,因为我在网上找不到一个例子?”类似的问题。
我有许多完全独立的(即“令人尴尬的并行”)进程,我想使用 C# 使用 .NET Framework 4 中的任务并行库并行运行这些进程。其中一些流程需要使用可通过 COM/OLE 自动化访问的软件。
具体来说,有一个 Parallel.Foreach() 循环从项目列表中划分任务,基本上调用 Parallel.Foreach 内的不同函数来处理处理(因此其中一些函数使用 COM 库来工作)。
这可能吗?谢谢。
This is an "is this possible, and if so can you give me a quick example because I can't find one online?" kind of question.
I have a number of completely separate (i.e. "embarrassingly parallel") processes that I want to run in parallel using the Task Parallel library in .NET Framework 4 using C#. Some of these processes require the use of software that can be accessed via COM/OLE automation.
Specifically, there is a Parallel.Foreach() loop that divides up the tasks from a list of items, basically calling a different function inside the Parallel.Foreach to handle the processing (so some of these functions employ COM libraries to work).
Is this possible? Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
将 COM 对象与 TPL 结合使用是 100% 可能的。虽然默认情况下 TPL 确实将使用标准 .NET ThreadPool,但 TPL 通过
TaskScheduler
类,它使您能够提供自己的调度程序,该调度程序可以将工作分派到您创建的线程。在使用 COM 对象的情况下,您首先需要知道 COM 类是否需要 STA 线程或 MTA 线程。如果是 MTA 线程,则无需执行任何特殊操作,因为 COM 类已可以从任何随机线程中使用。不幸的是,大多数经典的 COM 对象往往依赖于 STA 线程,此时您需要使用自定义
TaskScheduler
,以便您使用它们的任何 .NET 线程都已 初始化为 STA 兼容线程。虽然 TaskScheduler 的编写并不简单,但如果您对线程有基本的了解,那么编写它们也并不难。幸运的是,ParallelExtensions Extras 库 已经提供了一个
StaTaskScheduler
类,因此您不需要甚至不需要自己写任何东西。 PFX 这里有一篇很棒的博客文章团队讨论 StaTaskScheduler 类的实现和一些用例。但基本上,您需要在某个类的某处将一个新的
StaTaskScheduler
初始化为静态,然后启动您的Tasks
并指定它们由该实例调度。那看起来像这样:It's 100% possible to use COM objects with the TPL. While it's true that, by default, the TPL will use the standard .NET ThreadPool, the TPL has an extension point via the
TaskScheduler
class which enables you to provide your own scheduler which can dispatch work to threads which you've created.In the case of of using COM objects you first need to know if the COM class requires STA threading or MTA threading. If MTA threading, then there's nothing special that needs to be done because the COM class can already be used from any random thread. Unfortunately most classic COM objects tend to rely on STA threading and that's when you'd need to employ a custom
TaskScheduler
so that whatever .NET thread you're using them from has been initialized as an STA compatible thread.While TaskSchedulers are not exactly trivial to write, they're not really that hard to write either if you've got a basic understanding of threading. Luckily the ParallelExtensions Extras library already provides an
StaTaskScheduler
class so you don't even need to write anything yourself. There's a great blog post here by the PFX team that discusses the implementation of and some use cases for the theStaTaskScheduler
class.Basically though, you'll want to initialize a new
StaTaskScheduler
as a static somewhere on one of your classes and then just start yourTasks
specifying that they are scheduled by that instance. That would look something like this:这有可能,但也可能行不通。
许多 COM 对象需要特定的独立线程。当您使用 Parallel.For/ForEach 时,您正在 .NET ThreadPool 上运行,该线程池没有单元线程设置。这可能有效,并且适用于某些 COM 对象,但也可能导致崩溃和难以追踪的奇怪 COM 异常。
It's potentially possible, but it may also not work.
Many COM objects require a specific apartment threading. When you use Parallel.For/ForEach, you're running on the .NET ThreadPool, which doesn't have the apartment threading setup. This may work, and can for some COM objects, but can also cause crashes and strange COM exceptions that are difficult to track down.
我尚未验证一些其他信息,但这可能会有所帮助。默认任务调度程序将使用当前线程来完成一些工作,然后根据需要从线程池中添加其他线程。
如果您在执行 Parallel.ForEach 时共享 COM 对象,这可能会导致问题。例如,假设您的主线程是 STA。您可以在其上实例化 COM 对象,并使用 Parallel.ForEach 执行一些工作,其中每个线程都尝试访问先前实例化的 COM 对象。我怀疑它会损坏,并且初步测试似乎支持了这一点。在这种情况下,我至少看到几个选项:
Some additional information that I am yet to verify, but that may be helpful. The default task scheduler will use the current thread to do some of the work then add additional threads from the thread pool as necessary.
This could cause problems if you are sharing a COM object when doing Parallel.ForEach. For example, let's say your main thread is STA. You instantiate the COM object on that and use Parallel.ForEach to do some work where each thread tries to access the previously instantiated COM object. I suspect that it will break, and initial testing seems to back this up. In this scenario I see at least a couple of options: