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

这是“这是可能的,如果是这样,你能给我一个简单的例子,因为我找不到一个在线的吗?” 有点问题。

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

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

这可能吗? 谢谢。

使用TPL的COM对象是100%可能的。 虽然默认情况下TPL将使用标准.NET ThreadPool,但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); 

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

许多COM对象需要特定的单元线程 。 当您使用Parallel.For / ForEach时,您正在.NET ThreadPool上运行,它没有公寓线程设置。 这可能有效,并且可以用于某些COM对象,但也可能导致崩溃和难以追踪的奇怪COMexception。

我还要validation一些其他信息,但这可能会有所帮助。 默认任务调度程序将使用当前线程执行某些工作,然后根据需要从线程池中添加其他线程。

如果在执行Parallel.ForEach时共享COM对象,这可能会导致问题。 例如,假设您的主线程是STA。 您实例化COM对象并使用Parallel.ForEach做一些工作,其中每个线程尝试访问以前实例化的COM对象。 我怀疑它会破裂,初步测试似乎支持这一点。 在这种情况下,我至少看到了几个选项:

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