2011-02-10 17 views
11

Questo è un "è possibile, e se è così puoi darmi un rapido esempio perché non riesco a trovarne uno online?" tipo di domanda.La libreria parallela di attività .NET 4 può utilizzare oggetti COM?

Ho un numero di processi completamente separati (cioè "imbarazzanti paralleli") che voglio eseguire in parallelo usando la libreria Task Parallel in .NET Framework 4 usando C#. Alcuni di questi processi richiedono l'utilizzo di software a cui è possibile accedere tramite l'automazione COM/OLE.

In particolare, esiste un ciclo Parallel.Foreach() che divide le attività da un elenco di elementi, in pratica chiamando una funzione diversa all'interno di Parallel.Foreach per gestire l'elaborazione (quindi alcune di queste funzioni utilizzano librerie COM per lavoro).

È possibile? Grazie.

+4

Sembra un candidato perfetto per un test rapido ... provalo. – Oded

risposta

18

È possibile utilizzare al 100% gli oggetti COM con TPL. Mentre è vero che, per impostazione predefinita, il TPL utilizzerà lo standard .NET ThreadPool, il TPL ha un punto di estensione tramite the TaskScheduler class che consente di fornire il proprio programma di pianificazione che può inviare lavoro ai thread che hai creato.

In caso di utilizzo di oggetti COM è necessario innanzitutto sapere se la classe COM richiede il threading STA o il threading MTA. Se il threading MTA, quindi non c'è nulla di speciale che deve essere fatto perché la classe COM può già essere utilizzata da qualsiasi thread casuale. Sfortunatamente la maggior parte degli oggetti COM classici tendono a fare affidamento sul threading STA e in quel caso è necessario utilizzare un valore personalizzato TaskScheduler in modo che qualsiasi thread .NET dal quale li si sta utilizzando sia stato initialized as an STA compatible thread.

Mentre TaskSchedulers non sono esattamente banali da scrivere, non sono poi così difficili da scrivere se hai una conoscenza di base del threading. Fortunatamente lo the ParallelExtensions Extras library fornisce già una classe StaTaskScheduler in modo da non dover nemmeno scrivere nulla da soli. C'è il a great blog post here dal team PFX che discute l'implementazione di e alcuni casi d'uso per la classe StaTaskScheduler.

In linea di principio, è preferibile inizializzare un nuovo StaTaskScheduler come statico da qualche parte in una delle classi e quindi avviare semplicemente il proprio Tasks specificando che sono stati programmati da tale istanza. Sarebbe come:

// 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

Molto interessante, dovrò esaminare questo, grazie! Per riferimento, la funzionalità principale che sto cercando di ottenere è l'esecuzione parallela di diversi flussi di lavoro in R (http://www.r-project.org/). Riporterò qui se trovassi qualcosa. – user483679

+0

Grazie, esattamente quello di cui avevo bisogno. –

2

È potenzialmente possibile, ma potrebbe anche non funzionare.

Molti oggetti COM richiedono uno specifico apartment threading. Quando si utilizza Parallel.For/ForEach, si esegue .NET ThreadPool, che non dispone della configurazione del thread dell'appartamento. Questo può funzionare, e può funzionare per alcuni oggetti COM, ma può anche causare arresti anomali e strane eccezioni COM difficili da rintracciare.

0

Alcune informazioni aggiuntive che devo ancora verificare, ma che potrebbero essere utili. L'utilità di pianificazione predefinita utilizzerà il thread corrente per eseguire parte del lavoro, quindi aggiungerà ulteriori thread dal pool di thread, se necessario.

Ciò potrebbe causare problemi se si condivide un oggetto COM quando si esegue Parallel.ForEach. Ad esempio, supponiamo che il tuo thread principale sia STA. Si crea un'istanza dell'oggetto COM su quello e si utilizza Parallel.ForEach per eseguire alcune operazioni in cui ogni thread tenta di accedere all'oggetto COM precedentemente istanziato. Sospetto che si romperà e il test iniziale sembra confermarlo.In questo scenario vedo almeno un paio di opzioni:

  • Supponendo che l'oggetto COM supporti MTA, il thread chiamante utilizza MTA. Tuttavia questo potrebbe non essere un'opzione per altri motivi. Ad esempio, se l'applicazione è un'applicazione Windows Form, credo che Main() sia richiesto per avere l'attributo STAThread.
  • Utilizzare un programmatore di attività alternativo come StaTaskScheduler citato da Drew. È possibile avere tutti i thread STA o utilizzare uno scheduler che non utilizza il thread chiamante ed esegue tutti i thread MTA.
Problemi correlati