2011-02-10 16 views
11

Este es un "¿es esto posible, y si es así puede darme un ejemplo rápido porque no puedo encontrar uno en línea?" tipo de pregunta.¿Puede la Biblioteca paralela de tareas .NET 4 usar objetos COM?

Tengo un número de procesos completamente separados (es decir, "vergonzosamente en paralelo") que quiero ejecutar en paralelo utilizando la biblioteca Task Parallel en .NET Framework 4 usando C#. Algunos de estos procesos requieren el uso de software al que se puede acceder a través de la automatización COM/OLE.

Específicamente, hay un bucle Parallel.Foreach() que divide las tareas de una lista de elementos, básicamente llamando a una función diferente dentro del Paralelo.Foreach para manejar el procesamiento (por lo que algunas de estas funciones emplean bibliotecas COM para trabajo).

¿Esto es posible? Gracias.

+4

Parece el candidato perfecto para una prueba rápida ... pruébalo. – Oded

Respuesta

18

Es 100% posible utilizar objetos COM con el TPL. Si bien es cierto que, de forma predeterminada, el TPL utilizará el .NET ThreadPool estándar, el TPL tiene un punto de extensión a través del the TaskScheduler class que le permite proporcionar su propio programador que puede enviar el trabajo a los hilos que ha creado.

En el caso de usar objetos COM primero necesita saber si la clase COM requiere enhebrado STA o enhebrado MTA. Si se está enhebrando MTA, no hay nada especial que deba hacerse porque la clase COM ya puede usarse desde cualquier hilo aleatorio. Desafortunadamente, la mayoría de los objetos COM clásicos tienden a confiar en el enhebrado STA y es entonces cuando necesitas emplear un TaskScheduler personalizado para que el hilo .NET del que los estás usando haya sido initialized as an STA compatible thread.

Aunque los TaskSchedulers no son exactamente triviales de escribir, tampoco son realmente tan difíciles de escribir, si usted tiene una comprensión básica del enhebrado. Afortunadamente the ParallelExtensions Extras library ya proporciona una clase StaTaskScheduler por lo que ni siquiera necesita escribir nada usted mismo. Hay a great blog post here por parte del equipo de PFX que analiza la implementación y algunos casos de uso para la clase StaTaskScheduler.

Básicamente, aunque quiera inicializar un nuevo StaTaskScheduler como estático en alguna parte de una de sus clases, simplemente inicie su Tasks especificando que están programados para esa instancia. Eso sería algo como esto:

// 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); 
+0

Muy interesante, tendré que analizar esto, ¡gracias! Como referencia, la funcionalidad principal que intento lograr es la ejecución paralela de varios flujos de trabajo en R (http://www.r-project.org/). Informaré aquí si resuelvo algo. – user483679

+0

Gracias, exactamente lo que necesitaba. –

2

Es potencialmente posible, pero es posible que tampoco funcione.

Muchos objetos COM requieren un apartment threading específico. Cuando utiliza Parallel.For/ForEach, se ejecuta en .NET ThreadPool, que no tiene la configuración de subprocesamiento de apartamento. Esto puede funcionar, y puede para algunos objetos COM, pero también puede causar bloqueos y extrañas excepciones COM que son difíciles de rastrear.

0

Alguna información adicional que aún debo verificar, pero que puede ser útil. El planificador de tareas predeterminado usará el hilo actual para hacer parte del trabajo y luego agregará hilos adicionales del grupo de subprocesos según sea necesario.

Esto podría causar problemas si comparte un objeto COM al hacer Parallel.ForEach. Por ejemplo, digamos que su hilo principal es STA. Crea una instancia del objeto COM en eso y usa Parallel.ForEach para hacer algún trabajo donde cada thread intente acceder al objeto COM previamente instanciado. Sospecho que se romperá, y las pruebas iniciales parecen respaldar esto.En este escenario, veo al menos un par de opciones:

  • Suponiendo que el objeto COM es compatible con MTA, haga que el hilo que llama utilice MTA. Sin embargo, esto puede no ser una opción por otras razones. Por ejemplo, si la aplicación es una aplicación de Windows Forms, creo que Main() debe tener el atributo STAThread.
  • Utilice un planificador de tareas alternativo como el StaTaskScheduler mencionado por Drew. Puede tener todos los hilos STA o utilizar un programador que no utilice el hilo de llamada y ejecutar todos los hilos MTA.
Cuestiones relacionadas