2010-02-05 34 views
15

Tôi có một quy trình có thể có nhiều AppDomain. Mỗi AppDomain thu thập một số số liệu thống kê. Sau một thời gian nhất định, tôi muốn tích lũy những thống kê này và lưu chúng vào một tập tin.Chia sẻ dữ liệu giữa AppDomains

Một cách để làm điều này là Remoting, mà tôi muốn tránh.

Kỹ thuật duy nhất khác mà tôi có trong đầu là lưu từng dữ liệu của AppDomain trong một tệp và sau một thời gian cụ thể, một trong các AppDomain thu thập tất cả dữ liệu và tích lũy chúng.

Nhưng nó sẽ là lý tưởng nếu tất cả điều này có thể được thực hiện trong bộ nhớ, mà không có chi phí serializing thông tin để vượt qua giữa AppDomains. Ai có ý tưởng gì không?

Trả lời

12

Cách duy nhất để tránh tuần tự hóa là đại diện cho dữ liệu của bạn bằng cách sử dụng các đối tượng có nguồn gốc từ MarshalByRefObject, nhưng trong trường hợp đó bạn vẫn sẽ có chi phí marshalling trên các ranh giới AppDomain. Điều này cũng có thể liên quan đến việc tái cấu trúc/viết lại nhiều mã của bạn.

Giả sử marshalling bằng tham chiếu không phải là một tùy chọn, bạn sẽ phải serialise tại một số điểm. Nó đơn giản là không thể tránh được. Một cách để làm điều này là như Neil Barnwell gợi ý, với một cơ sở dữ liệu, một cách khác sẽ là với một tệp cục bộ như bạn tự đề xuất.

Một cách khác có thể hoặc không khả thi tùy thuộc vào thời gian giao hàng của bạn và/hoặc việc chấp nhận .NET 4.0, sẽ sử dụng tệp ánh xạ bộ nhớ, xem .Net Framework 4.0: Using memory mapped files.

+0

Tôi chưa viết mã. Chỉ cần làm việc trên thiết kế. Bạn có thể cho tôi biết về bất kỳ bài viết nào giải thích việc chia sẻ dữ liệu bằng cách sử dụng phương pháp đầu tiên bạn đăng không? – ata

+0

Marshaling bằng cách tham chiếu sẽ tuần tự hóa dữ liệu, quá, nhưng trong phần nhỏ. Mỗi cuộc gọi phương thức sẽ trả về một chút thông tin có hiệu quả tuần tự hóa một chút dữ liệu. Đây có lẽ là một ý tưởng hay nếu bạn chỉ yêu cầu một phần nhỏ dữ liệu. Nhưng nếu bạn phải xử lý (gần như) toàn bộ dữ liệu, nhận được nó từng chút một với nhiều cuộc gọi tên miền chéo sẽ không thể tin được so với việc tuần tự hóa và truyền dữ liệu cùng một lúc. –

+2

Nếu bạn đi theo con đường này, đừng quên ghi đè phương thức InitializeLifetimeService; điều đó đã khiến tôi phát điên một vài ngày trước ("Object" ... "đã bị ngắt kết nối hoặc không tồn tại ở máy chủ.") –

3

Tôi đánh giá cao bạn muốn giữ điều này trong bộ nhớ, nhưng đề xuất đầu tiên của tôi là ghi dữ liệu vào cơ sở dữ liệu và truy vấn từ đó. Remoting vẫn là một cuộc gọi từ xa, đó là nơi mà nhiều "chi phí" của việc sử dụng một máy chủ cơ sở dữ liệu đến từ, và bạn phải xây dựng trong xử lý giao dịch để đảm bảo rằng bạn không bị mất dữ liệu. Nếu bạn viết thư cho cơ sở dữ liệu SQL Server, bạn có hỗ trợ giao dịch sẵn sàng và đang chờ bạn, và nó nhanh chóng nhanh cho các truy vấn.

+0

Trong khi nó có thể là một ý tưởng tốt để sử dụng một cơ sở dữ liệu và có các dữ liệu vẫn kiên trì và giải quyết cho vấn đề giao tiếp với một công nghệ thành lập, tôi không nghĩ rằng giao dịch sẽ là một lợi ích quan trọng . Nếu miền ứng dụng nguồn gặp sự cố, dữ liệu sẽ bị mất bất kể nó chỉ nằm trên dây đến cơ sở dữ liệu hoặc trong luồng bộ nhớ. –

4

Tôi có xu hướng nói chỉ cần sử dụng tính năng truy cập từ xa. Việc ghi dữ liệu vào một tệp cũng yêu cầu tuần tự hóa. Serialization dường như là gần như không thể tránh khỏi những gì bao giờ công nghệ bạn sử dụng. Bạn phải chuyển dữ liệu từ miền ứng dụng này sang miền ứng dụng khác bằng cách sử dụng một số kênh và bạn sẽ phải tuần tự hóa dữ liệu để truyền dữ liệu qua kênh.

Cách duy nhất để tránh tuần tự hóa có vẻ là sử dụng bộ nhớ dùng chung để cả hai miền ứng dụng có thể truy cập dữ liệu mà không bao giờ đi qua kênh. Ngay cả việc nhân bản sâu dữ liệu từ bộ nhớ của một miền ứng dụng vào bộ nhớ của người khác là cốt lõi của nó không có gì sau đó là một chuỗi tuần tự hóa nhị phân (nơi kết quả không nhất thiết được lưu trữ trong các vị trí bộ nhớ liên tiếp).

+0

Remoting cũng liên quan đến Reflection. Đó là Serialization + Reflection. Mặt khác, dữ liệu của tôi chỉ là một số giá trị dài và gấp đôi mà tôi có thể viết trong tập tin mà không tốn nhiều chi phí. – ata

+6

Bạn đang nhìn vào các điểm sai. Các nút cổ chai của việc sử dụng một tập tin là truy cập đĩa và sẽ mất vài phần nghìn giây và tốc độ truyền tải cho phép bạn chuyển xuống dưới một trăm megabyte mỗi giây. Tôi không chắc chắn những gì nút cổ chai thực tế của remoting là (theo như tôi nhớ hiệu suất bị giới hạn bởi số lượng cuộc gọi tên miền chéo, không phải số lượng dữ liệu chuyển giao) nhưng nó có thể chuyển vài trăm megabyte mỗi giây giữa các miền ứng dụng . Các chuỗi truy cập từ xa bằng cách sử dụng đường dẫn nhanh đạt được tốc độ truyền của vài gigabyte trên giây. –

20

Có thể chia sẻ dữ liệu giữa các miền AppDomain mà không cần chi phí Marshalling. Nhưng nó là một cách khá hacky. Bạn có thể tạo một đối tượng dữ liệu nguồn được chia sẻ bởi tham chiếu giữa tất cả các miền AppDomain. Bằng cách này, bạn sẽ nhận được tất cả dữ liệu vào một đối tượng được chia sẻ mà không cần chi phí của Marshalling. Âm thanh quá dễ để trở thành sự thật?

Điều đầu tiên là biết cách chia sẻ dữ liệu giữa các miền AppDomain mà không cần Marshalling. Đối với điều này, bạn nhận được địa chỉ đối tượng của đối tượng nguồn dữ liệu của bạn thông qua Marshal.UnsafeAddrOfPinnedArrayElement. Sau đó, bạn chuyển IntPtr này cho tất cả các miền AppDomain quan tâm đến điều này. Trong mục tiêu AppDomain bạn cần phải cast IntPtr này trở lại một tham chiếu đối tượng có thể được thực hiện JIT :: CastAny được thực hiện nếu bạn trả về một đối tượng từ một phương thức và đẩy con trỏ của nó vào trong ngăn xếp.

Viola bạn đã chia sẻ một đối tượng dưới dạng con trỏ đơn giản giữa AppDomain và bạn nhận được InvalidCastExceptions. Vấn đề là bạn phải đặt cho tất cả AppOomains LoaderOptimization của bạn.MultiDomain để đảm bảo rằng assembly xác định kiểu dữ liệu chia sẻ được nạp như là kiểu trung gian AppDomain có cùng con trỏ Method Table giữa tất cả các AppDomains.

Bạn có thể tìm thấy một ứng dụng ví dụ thực hiện chính xác điều này như một phần của WMemoryProfiler. Xem liên kết này để biết thêm detailed explanation and download link vào mã mẫu.

Mã cơ bản là

[LoaderOptimization(LoaderOptimization.MultiDomain)] 
static public void Main(string[] args) 
{ 

    // To load our assembly appdomain neutral we need to use MultiDomain on our hosting and child domain 
    // If not we would get different Method tables for the same types which would result in InvalidCastExceptions 
    // for the same type. 
    var other = AppDomain.CreateDomain("Test"+i.ToString(), AppDomain.CurrentDomain.Evidence, new AppDomainSetup 
     { 
      LoaderOptimization = LoaderOptimization.MultiDomain, 
     }); 

    // Create gate object in other appdomain 
    DomainGate gate = (DomainGate)other.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, typeof(DomainGate).FullName); 

    // now lets create some data 
    CrossDomainData data = new CrossDomainData(); 
    data.Input = Enumerable.Range(0, 10).ToList(); 

    // process it in other AppDomain 
    DomainGate.Send(gate, data); 

    // Display result calculated in other AppDomain 
    Console.WriteLine("Calculation in other AppDomain got: {0}", data.Aggregate); 
    } 
} 
+0

Câu trả lời thực sự hay. Tôi đã lần đầu tiên nghi ngờ việc chia sẻ cùng một đối tượng giữa hai AppDomains như thế này sẽ gây ra sự phá hoại với nguyên nhân GC của bất kỳ đối tượng nào được bỏ ghim (chỉ một đối tượng được chia sẻ được ghim). Nhưng khi bạn phác thảo độc đáo trong bài viết của mình thì chỉ có một GC trên tất cả các miền AppDomain, vì vậy nó hoạt động. Những thứ tuyệt vời! – nitrogenycs

Các vấn đề liên quan