2011-02-10 30 views
11

Đây là "điều này là có thể, và nếu như vậy bạn có thể cho tôi một ví dụ nhanh vì tôi không thể tìm thấy trực tuyến?" loại câu hỏi.Thư viện song song .NET 4 Task có sử dụng các đối tượng COM không?

Tôi có một số quy trình hoàn toàn riêng biệt (tức là "lúng túng song song") mà tôi muốn chạy song song bằng cách sử dụng thư viện Task Parallel trong .NET Framework 4 bằng C#. Một số quy trình này yêu cầu sử dụng phần mềm có thể được truy cập thông qua tự động hóa COM/OLE. Cụ thể, có một vòng lặp Parallel.Foreach() phân chia các nhiệm vụ từ một danh sách các mục, về cơ bản gọi một hàm khác bên trong Parallel.Foreach để xử lý việc xử lý (vì vậy một số hàm này sử dụng các thư viện COM để công việc).

Điều này có khả thi không? Cảm ơn.

+4

Âm thanh như một ứng cử viên hoàn hảo để thử nghiệm nhanh ... hãy dùng thử. – Oded

Trả lời

18

Có thể sử dụng các đối tượng COM với TPL 100%. Mặc dù, theo mặc định, TPL sẽ sử dụng tiêu chuẩn .NET ThreadPool, TPL có một điểm mở rộng thông qua the TaskScheduler class cho phép bạn cung cấp lịch trình của riêng bạn có thể gửi công việc tới các chủ đề mà bạn đã tạo.

Trong trường hợp sử dụng các đối tượng COM trước tiên bạn cần phải biết nếu lớp COM yêu cầu luồng STA hoặc luồng MTA. Nếu MTA luồng, sau đó không có gì đặc biệt mà cần phải được thực hiện bởi vì lớp COM có thể đã được sử dụng từ bất kỳ chủ đề ngẫu nhiên. Thật không may hầu hết các đối tượng COM cổ điển có xu hướng dựa vào luồng STA và đó là khi bạn cần sử dụng một tùy chỉnh TaskScheduler sao cho bất kỳ chuỗi .NET nào bạn đang sử dụng chúng đều là initialized as an STA compatible thread.

Trong khi TaskSchedulers không phải là chính xác tầm thường để viết, họ không thực sự là khó để viết, hoặc nếu bạn đã có một sự hiểu biết cơ bản về luồng. May mắn là the ParallelExtensions Extras library đã cung cấp một lớp học StaTaskScheduler vì vậy bạn thậm chí không cần phải viết bất cứ điều gì cho mình. Có a great blog post here bởi nhóm PFX thảo luận về việc triển khai và một số trường hợp sử dụng cho lớp StaTaskScheduler.

Về cơ bản, bạn sẽ muốn khởi tạo StaTaskScheduler mới ở dạng tĩnh ở đâu đó trên một trong các lớp học của bạn và sau đó chỉ cần bắt đầu Tasks xác định rằng chúng được lên lịch bởi trường hợp đó. Điều đó sẽ trông giống như sau:

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

Rất thú vị, tôi sẽ phải xem xét điều này, cảm ơn! Để tham chiếu, chức năng chính mà tôi đang cố gắng đạt được là thực hiện song song một số luồng công việc trong R (http://www.r-project.org/). Tôi sẽ báo cáo lại ở đây nếu tôi tìm ra bất cứ điều gì. – user483679

+0

Cảm ơn, chính xác những gì tôi cần. –

2

Nó có khả năng có thể, nhưng nó cũng có thể không hoạt động.

Nhiều đối tượng COM yêu cầu cụ thể apartment threading. Khi bạn sử dụng Parallel.For/ForEach, bạn đang chạy trên .NET ThreadPool, không có thiết lập luồng căn hộ. Điều này có thể làm việc, và có thể cho một số đối tượng COM, nhưng cũng có thể gây ra sự cố và các ngoại lệ COM lạ mà khó theo dõi.

0

Một số thông tin bổ sung mà tôi chưa xác minh, nhưng điều đó có thể hữu ích. Trình lên lịch tác vụ mặc định sẽ sử dụng chuỗi hiện tại để thực hiện một số công việc sau đó thêm các chuỗi bổ sung từ nhóm chủ đề nếu cần.

Điều này có thể gây ra sự cố nếu bạn đang chia sẻ đối tượng COM khi thực hiện Parallel.ForEach. Ví dụ, giả sử chủ đề chính của bạn là STA. Bạn khởi tạo đối tượng COM trên đó và sử dụng Parallel.ForEach để thực hiện một số công việc mà mỗi luồng cố gắng truy cập đối tượng COM đã được khởi tạo trước đó. Tôi nghi ngờ rằng nó sẽ phá vỡ, và thử nghiệm ban đầu dường như trở lại này lên.Trong trường hợp này, tôi thấy ít nhất một vài tùy chọn:

  • Giả sử đối tượng COM hỗ trợ MTA, có chuỗi gọi sử dụng MTA. Tuy nhiên, điều này có thể không phải là một lựa chọn vì các lý do khác. Ví dụ, nếu ứng dụng là một ứng dụng Windows Forms, tôi tin rằng Main() được yêu cầu có thuộc tính STAThread.
  • Sử dụng trình lập lịch tác vụ thay thế chẳng hạn như StaTaskScheduler được Drew đề cập. Bạn có thể có tất cả các chủ đề STA hoặc sử dụng một bộ lập lịch mà không sử dụng thread gọi và chạy tất cả các chủ đề MTA.