Может ли библиотека .NET 4 Task Parallel Library использовать COM-объекты? - PullRequest
11 голосов
/ 11 февраля 2011

Это «возможно ли это, и если да, можете ли вы привести мне быстрый пример, потому что я не могу найти один в Интернете?»Вопрос такого рода.

У меня есть ряд совершенно отдельных (то есть «смущающих параллель») процессов, которые я хочу запускать параллельно, используя библиотеку Task Parallel в .NET Framework 4 с использованием C #.Некоторые из этих процессов требуют использования программного обеспечения, доступ к которому можно получить с помощью автоматизации COM / OLE.

В частности, существует цикл Parallel.Foreach (), который отделяет задачи от списка элементов, в основном вызываядругая функция внутри Parallel.Foreach для обработки (поэтому некоторые из этих функций используют библиотеки COM для работы).

Возможно ли это?Спасибо.

Ответы [ 3 ]

18 голосов
/ 12 февраля 2011

На 100% возможно использование COM-объектов с TPL.Хотя это правда, что по умолчанию 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);
2 голосов
/ 11 февраля 2011

Это потенциально возможно, но может и не работать.

Многие COM-объекты требуют определенной многопоточности .Когда вы используете Parallel.For / ForEach, вы работаете в .NET ThreadPool, который не имеет настройки потоков в квартире.Это может работать, а может и для некоторых объектов COM, но также может вызывать сбои и странные исключения COM, которые трудно отследить.

0 голосов
/ 02 июля 2012

Некоторая дополнительная информация, которую мне еще предстоит проверить, но она может оказаться полезной. Планировщик задач по умолчанию будет использовать текущий поток для выполнения некоторой работы, а затем добавлять дополнительные потоки из пула потоков по мере необходимости.

Это может вызвать проблемы при совместном использовании COM-объекта при выполнении Parallel.ForEach. Например, скажем, ваш главный поток - STA. Вы создаете экземпляр COM-объекта и используете Parallel.ForEach для выполнения некоторой работы, когда каждый поток пытается получить доступ к ранее созданному COM-объекту. Я подозреваю, что это сломается, и первоначальное тестирование, кажется, подтверждает это. В этом сценарии я вижу как минимум пару вариантов:

  • Предполагая, что COM-объект поддерживает MTA, пусть вызывающий поток использует MTA. Однако это не может быть вариантом по другим причинам. Например, если приложение является приложением Windows Forms, я считаю, что Main () должен иметь атрибут STAThread.
  • Используйте альтернативный планировщик задач, такой как StaTaskScheduler, упомянутый Дрю. Вы можете иметь все потоки STA или использовать планировщик, который не использует вызывающий поток, и запускать все потоки MTA.
...