.NET 4任务并行库可以使用COM对象吗?

11

这是一个“这是否可能,如果可能的话,你能给我一个快速的例子吗?因为我在网上找不到。”的问题。

我有许多完全独立(即“尴尬地并行”)的进程,我想使用C#中的.NET Framework 4中的任务并行库并行运行它们。其中一些进程需要使用可以通过COM/OLE自动化访问的软件。

具体来说,有一个Parallel.Foreach()循环,它将任务从项目列表中分割出来,基本上调用Parallel.Foreach内部的不同函数来处理处理(因此其中一些函数使用COM库工作)。

这是否可能?谢谢。


4
听起来这个人是进行快速测试的完美人选...试一试吧。 - Oded
3个回答

18
使用TPL可以完全使用COM对象。虽然默认情况下,TPL将使用标准的.NET线程池,但TPL通过TaskScheduler提供了扩展点,使您能够提供自己的调度程序,可以将工作分派到您创建的线程。
在使用COM对象的情况下,首先需要知道COM类是否需要STA线程或MTA线程。如果是MTA线程,则不需要做任何特殊处理,因为COM类已经可以从任何随机线程中使用。不幸的是,大多数经典的COM对象倾向于依赖STA线程,这时需要使用自定义的TaskScheduler,以便您所使用的任何.NET线程都已初始化为STA兼容线程
虽然TaskSchedulers并不是很容易编写,但如果您对线程有基本的了解,它们也不是非常难编写。幸运的是,ParallelExtensions Extras库已经提供了一个StaTaskScheduler类,因此您甚至无需编写任何内容。PFX团队在这里提供了一篇很棒的博客文章,讨论了StaTaskScheduler类的实现和一些用例。
基本上,您需要在某个类的静态位置初始化一个新的StaTaskScheduler,然后只需启动指定由该实例安排的Tasks。看起来会像这样:
// Create a static instance of the scheduler specifying some max number of threads
private static readonly StaTaskScheduler MyStaTaskScheduler = new StaTaskScheduler(4);

....

// Then specify the scheduler when starting tasks that need STA threading
Task.TaskFactory.StartNew(
() =>
{
    MyComObject myComObject = new MyComObject();

    myComObject.DoSomething();

    // ... etc ...
},
CancellationToken.None,
TaskCreationOptions.None,
MyStaTaskScheduler);

非常有趣,我得去研究一下,谢谢!为了参考,我试图实现的主要功能是在R(http://www.r-project.org/)中并行执行多个工作流程。如果我有所发现,我会在这里回报的。 - user483679
代码示例中 StaTaskScheduler 类的链接已经过时。当前链接在这里 - Damian Ubowski

2

这有可能是可行的,但也可能不起作用。

许多COM对象需要特定的单元线程。当您使用Parallel.For/ForEach时,您正在运行.NET线程池,该线程池没有设置单元线程。这可能有效,并且对于某些COM对象可以正常工作,但也可能导致崩溃和奇怪的COM异常,这些异常很难跟踪。


0

以下是一些我尚未验证但可能有用的额外信息。默认任务调度程序将使用当前线程执行部分工作,然后根据需要从线程池添加其他线程。

如果在Parallel.ForEach中共享COM对象,则可能会出现问题。例如,假设您的主线程是STA。您在该线程上实例化COM对象并使用Parallel.ForEach执行一些工作,其中每个线程都尝试访问先前实例化的COM对象。我怀疑它会崩溃,并且初始测试似乎支持这一点。在这种情况下,我至少看到了几个选择:

  • 假设COM对象支持MTA,请调用线程使用MTA。但是,由于其他原因,这可能不是一个选项。例如,如果应用程序是Windows Forms应用程序,则我认为Main()需要具有STAThread属性。
  • 使用另一种任务调度程序,例如Drew提到的StaTaskScheduler。您可以使用所有STA线程或使用不使用调用线程并运行所有MTA线程的调度程序。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接